Not able to login after encrypting the username - javascript

I have 2 fields username and password, while registering the user I am encrypting the username with AES and store into database, now I am unable to login because the plain text is not matching with encrypted data.
How can I resolve this problem?
P.s.-
1)I am using Crypto.js library
2)While login I can't again encrypt the username again as it is giving different encrypted data.

What you are trying to achieve is usually done with a hash. A hash function of the username will always return the same hash value.
If there is a specific reason for encrypting the username rather than hashing (which you haven’t explained though), then you will need to decrypt it in order to compare the values or use an encryption mode that is deterministic and does not involve a random initialization vector. See this question and its answers for details.

On your login logic, you should use the same AES encryption to encrypt the user 's input username during their login.
If the username is actually in your database, using that encrypted username should be able to query/locate the username in your database.
Below are for your reference on how the encrypt and decrypt works (copied from HERE):
var CryptoJS = require("crypto-js");
// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString();
// Decrypt
var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');
var originalText = bytes.toString(CryptoJS.enc.Utf8);
console.log(originalText); // 'my message'

Related

Can a JWT produced with RS256 be decoded by the jwt.io website?

recently I made my first Express server and added user authentication using jwt. Now I'm looking for a way to encrypt that jwt so that users will not be able to see the payload in the https://jwt.io website.
Does anyone know if this encryption algorithm will prevent the users from seeing the payload without the public / private key?
RS256 uses digital signature to ensure Integrity, Authenticity, and Non-repudiation on the produced token. It does not ensure Confidentiality.
If you want to use JWE (JSON Web Encryption) with JWT you can. And since you are both the issuer and recipient of the token I would suggest to use symmetric encryption. Actually you may not use asymmetric crypto because anyone with the possession of the public key would be able to encrypt and you cannot ensure you are actually the one who originally produced the JWE.
You need an implementation/library that supports JWE formatted JWTs. That would give you Integrity, Authenticity, and Confidentiality. e.g.:
npm install jose#4
To encrypt use EncryptJWT
import * as crypto from 'crypto'
import { EncryptJWT } from 'jose'
const secretKey = crypto.randomBytes(32) // you would pass your own 32 byte secret as a Buffer
const jwt = await new EncryptJWT({ 'urn:example:claim': true })
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
.setIssuedAt()
.setIssuer('urn:example:issuer')
.setAudience('urn:example:audience')
.setExpirationTime('2h')
.encrypt(secretKey)
This produces a JWE-formatted JWT like so that, without the knowledge of secretKey, cannot have its payload decrypted.
eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..Wz7DdwAPlbq4cYxn.OMfWJTMuyfLcdN4g541KfcDFKaL5y2bBaFIxuC_-mVa7YLE4M7bVfiO9R2umvpD_acGj5l3gvxulcRnHzBMeRpm4qgbJuWVdA1fYUOguDs1h2xtesZ_9iZUEtcu3hEJ1wVM46ad-9dPebe_VaWwe4XVU5GM.7lDflVFg_Qm3N88xX8Dy1A
To decrypt and validate the JWT Claim Set use jwtDecrypt
import { jwtDecrypt } from 'jose'
const { payload, protectedHeader } = await jwtDecrypt(jwt, secretKey, {
issuer: 'urn:example:issuer',
audience: 'urn:example:audience'
})

i am creating login api and hashed password using bcrypt

I want to create a register login logout system. at time of registration i am taking email and password
and storing hashed password. now when logging in i want to compare password entered to hashed password. so basically I want to know how can I compare and check plain password with hashed passwords
I think this is a duplicate question but am not able to mark it as such.
This should work, taken from the bcryptJS docs.
Sync
// Load hash from your password DB.
bcrypt.compare(myPlaintextPassword, hash, function(err, result) {
// result == true
});
Promise
// Load hash from your password DB.
bcrypt.compare(myPlaintextPassword, hash).then(function(result) {
// result == true
});

Approach to modify the database without logging the user?

I have a React frontend with a Node + MySQL backend, I'm sending an email to an user with two buttons to accept or decline a quote. What I'm trying to achieve is to make the buttons in the email modify the database securely without the user having to log into his account. My idea is to have two routes, one that sends the email containing the buttons which will have a url to my website with the jwt token on its parameters, and another for verifying said token and making the changes to the db. Here's some pseudo-code:
app.post("/email-quote", async function (req, res) {
const payload = {
uid: req.body.user.id,
quoteId: req.body.quote.id,
accepted: // true for the accept button, false for the decline button
}
const secret = ?
const token = jwt.sign(payload, secret);
// ...
// Generate and send email with buttons containing the url + the token
});
When the user clicks one of the buttons, I re-direct him to my website and there I can extract the token and verify its validity:
app.get("/verify-email-quote/:token", async function (req, res) {
const decodedJwt = jwt.decode(req.params.token);
const secret = ?
const verifiedJwt = jwt.verify(req.params.token, secret);
if (verifiedJwt) {
// Make the changes to the db
}
});
I wasn't able to find any examples trying to achieve something similar on the web, so I have these questions:
Would a jwt token be a good approach to achieve this?
If yes, what secret should I use to create the token?
If no, what other solutions could I look into?
Yes, you can do it this way.
The secret does not matter. As long as the secret is secret
It doesn't need to be a jwt token. It can just be a normal token. The incentive to using jwt is that you can embed a payload into the token. For your case, it looks like it is exclusively for verification purposes. It doesn't matter in the grand scheme of things, but if you don't have jwt already implemented, there's no need to go through all that extra work just for this use case.

Problems when using AES crypto between Node and CryptoJS in browser

I want encrypt a string with Node, and decrypt the string with CryptoJS in browser.
Encrypt:
var crypto = require('crypto');
function encrypt(txt, cryptkey) {
var cipher = crypto.createCipher('aes-256-cbc', cryptkey);
var crypted = cipher.update(txt, 'utf8', 'hex');
crypted += cipher.final('hex');
return crypted;
}
encrypt('1', 'key'); // 83684beb6c8cf063caf45cb7fad04a50
Include:
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
Decrypt:
var decrypted = CryptoJS.AES.decrypt('83684beb6c8cf063caf45cb7fad04a50', 'key');
console.log(decrypted.toString(CryptoJS.enc.Utf8)); // empty string
The actual result is empty string.
What is the right way to decrypt data from node?
CryptoJS supports the same password-based encryption mode that the crypto module in node.js supports which is implemented as the equivalent to EVP_BytesToKey. CryptoJS generates a random salt by default, but node.js doesn't and uses an empty salt. An empty salt is bad and should not be used. Also, it's not secure to derive a key from a password with this method. One needs to use PBKDF2 (supported by CryptoJS and node.js) or similar with a lot of iterations and a random salt.
var ctHex = '83684beb6c8cf063caf45cb7fad04a50';
var ct = CryptoJS.enc.Hex.parse(ctHex);
var salt = CryptoJS.lib.WordArray.create(0); // empty array
var decrypted = CryptoJS.AES.decrypt({ciphertext: ct, salt: salt}, 'key');
document.querySelector("#dec").innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "1"<br/>Got: "<span id="dec"></span>"
You said that this will be done over HTTP.
If you want to use transport security without user intervention, then this is completely insecure, because the key needs to be transmitted alongside of the ciphertext which makes this at best obfuscation.
If the user and the server both know the password before communication, then this is still insufficient, because the key derivation that both CryptoJS and node.js provide is insufficient and something like PBKDF2 must be used. MD5 is easily brute-forceable.
You would need to use asymmetric cryptography to protect this communication against a passive attacker (one that cannot inject arbitrary packets into the stream between server and client). I suggest that you generate an RSA key pair and sent the public key to the client so that the client can encrypt a message to the server. You can use forge for that.
Encryption would look like this:
var salt = CryptoJS.lib.WordArray.create(0); // empty array
var params = CryptoJS.kdf.OpenSSL.execute('key', 256/32, 128/32, salt);
var pt = '1';
var encrypted = CryptoJS.AES.encrypt(pt, params.key, {iv: params.iv});
document.querySelector("#enc").innerHTML = encrypted.ciphertext.toString();
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
Expected: "83684beb6c8cf063caf45cb7fad04a50"<br/>Got: "<span id="enc"></span>"

How to decipher string in node js which is encrypted in crypto js in javascript

My client side code:
data.username = CryptoJS.AES.encrypt(user.username, "password");
data.password = CryptoJS.AES.encrypt(user.password, "password");
Then I am sending 'data' to server which is express.js
var user = req.body;
var decipher = crypto.createDecipher('aes256', "password");
var decrypted = decipher.update(user.username, 'hex', 'utf-8');
decrypted += decipher.final('utf-8');
I am getting this error:
Error: DecipherInit error
at new Decipher (crypto.js:368:17)
at Object.Decipher (crypto.js:365:12)
CryptoJS' encrypt function with a password uses the same EVP_BytesToKey function node.js' createCipher, with the important difference that CryptoJS uses a random salt to derive whereas node does not (emphasis mine):
Note: createCipher derives keys with the OpenSSL function EVP_BytesToKey with the digest algorithm set to MD5, one iteration, and no salt.
Either you directly use CryptoJS in node which is possible, because CryptoJS doesn't have any dependencies, or you do the key derivation yourself on both ends and use crypto.createCipheriv. If you do the former, you would have to additionally pass the salts of the username and password encryptions to node.
Note that data.username is the CryptoJS cipherParams object which contains the salt and the IV, but when you convert this to string with data.username.toString(), the salt is not included anymore, but the IV is. This is not the data that you would put into the node.js functions. Send data.username.ciphertext instead.

Categories

Resources