Issues running crypto-js on Parse Cloud Code for iOS application - javascript

I'm using Parse as my backend for my iOS application and would like to encrypt all the data that's sent between Parse and my iOS device. As such, I'm using Parse Cloud Code in hopes of being able to perform server-side encryption & decryption to process all data it sends and receives.
Apparently Parse has a 'crypto' module by default, but since I've been unable to find any documentation for it, I've gone ahead and tried using crypto-js by copying the appropriate files for AES encryption + decryption into my Parse Cloud Code /cloud folder.
The issue I'm running into is that I'm not sure what class of object is being returned by crypto-js's AES encryption / decryption function. I *seem* to be getting back an NSDictionary object but have no idea what to do with it. I would have guessed that I would receive an NSString or NSData object, but I seem to have guessed wrong.
Please let me know what additional information I can provide or what incorrect assumptions I may have made.

I needed to encrypt / decrypt on the server side, here is my cloud code which is similar to nodeJS code:
var crypto = require('crypto');
var cryptoAlgorithm = "aes-128-cbc"; //or whatever you algorithm you want to choose see http://nodejs.org/api/crypto.html
var cryptoPassword = "theLongAndRandomPassphrase";
var cipher = crypto.createCipher(cryptoAlgorithm,cryptoPassword);
var decipher = crypto.createDecipher(cryptoAlgorithm,cryptoPassword);
exports.myCiphering = {
encrypt:function(text){
var encrypted = cipher.update(text,'utf8','hex')
encrypted += cipher.final('hex');
return encrypted;
},
decrypt: function(text){
var decrypted = decipher.update(text,'hex','utf8')
decrypted += decipher.final('utf8');
return decrypted;
}
};
If this snippet has been saved in "cloud/ciphering.js", you can then use the ciphering tool like this anywhere in cloud code:
var text = "encryptMe";
var ciphering = require("cloud/ciphering.js").myCiphering;
var encrypted = ciphering.encrypt(text);
var decrypted = ciphering.decrypted(encrypted);
if (decrypted == text){
//the "password" is correct
}

Since Parse uses SSL all data is sent encrypted, SSL is enough to secure the communications.
You may want to encrypt the data so that it is protected on the server but unless you really understand cryptographic security don't.
Plain or encrypted passwords should never be stored, store a properly salted and hashed version of the password.
If you feel your data is substantially valuable enough have a security domain expert design it. Getting security right is hard, one mistake will invalidate it all.

Related

Is there a way to generate RSA key pair client side with javascript?

I used Cryptico library and it is working fine, but the public key from Cryptico is not compatible with OpenSSL (meaning I can not use it to encrypt data with PHP as an example). I am asking how can I generate a key pair client side with the public key being compatible with OpenSSL. The goal is being able to encrypt data with the public key on IOS, Android or PHP and decrypt it on Javascript (meaning it is compatible cross platforms).
You may use jsbn library in the link below:
http://www-cs-students.stanford.edu/~tjw/jsbn/
and you may see the demo here:
http://www-cs-students.stanford.edu/~tjw/jsbn/rsa2.html
This is the most popular library you may find and you have the chance to customize it based on your requirement.
Also, you have another option with jsencrypt which is available here:
https://github.com/travist/jsencrypt
It is also compatible with openssl.
// Encrypt with the public key...
var encrypt = new JSEncrypt();
encrypt.setPublicKey($('#pubkey').val());
var encrypted = encrypt.encrypt($('#input').val());
// Decrypt with the private key...
var decrypt = new JSEncrypt();
decrypt.setPrivateKey($('#privkey').val());
var uncrypted = decrypt.decrypt(encrypted);
// Now a simple check to see if the round-trip worked.
if (uncrypted == $('#input').val()) {
alert('It works!!!');
}
else {
alert('Something went wrong....');
}

I am using PyNacl at the backend for digital signatures. Which library should I use at frontend?

I have created an API that validates data based on PyNacl at the backend. I am accepting length 64 hexadecimal-encoded sender and recipient account numbers for my simple Crypto API and validating the signature based on PyNacl library. I was wondering what Javascript library to use on my frontend so that the data I send using my React-based, it is coherent to my backend API. I looked at tweetnacl, but am not sure if they have the same working pattern. Can you give me some information about whether or not I can use tweetnacl, or will I have to create a python script that uses PyNacl to generate Signing Keys / Verify Keys, and signs the message?
Thanks.
Update! We have been successful at passing files between TweetLua and PyNaCl! The person writing the Lua side of the code had an "off by one" error (silly, but aren't most of our errors?). Once we got the right pieces in their proper places, it was a snap.
I know the use of Lua instead of JavaScript isn't a perfect match to this question, but I hope that people who find this will get some use all the same. It boils down to: Yes, TweetNaCl and PyNaCl are compatible, just as you'd expect.
Important element in this process:
TweetNaCl takes the MAC, Nonce, P_key, and K_key as separate arguments when boxing and unboxing.
PyNaCl does NOT. Capture the sender's P_key, import it, make a box, and then pass the remaining cyphertext through as a unit. PyNaCl will pull out the Nonce and MAC for you.
Lua encryption:
local function main(flag, files, keys)
local pt = chunkpt(flag, files) # We broke large files down
files.fout_size = companyfilesize(flag, pt)
files.fout = assert(io.open(flag.outfile, "wb"))
local current = files.fout:seek()
files.fout:seek("set", files.fout_size - 1)
files.fout:write("x")
files.fout:seek("set", current)
local err
local ct = {}
local nonce = {}
local mac = {}
local root
local nonceroot
local macroot
local n = #pt
for i = n, 1, -1 do
nonce[i] = nacl.randombytes(NONCE_LEN)
if i == n then
ct[i], err = nacl.box(pt[i], nonce[i], keys.p_rx, keys.k)
if err ~= nil then error("boxing error") end
else
ct[i], err = nacl.box(pt[i] .. nonce[i + 1] .. mac[i + 1], nonce[i],
keys.p_rx, keys.k)
if err ~= nil then error("boxing error") end
end
mac[i] = ct[i]:sub(1, MAC_LEN)
ct[i] = ct[i]:sub(MAC_LEN + 1, -1)
end
files.fout:seek("set", 0)
local header = header_info
files.fout:write(header)
files.fout:write(keys.p_tx)
files.fout:write(nonce[1])
files.fout:write(mac[1])
files.fout:write(ct[1])
files.fin:close()
files.fout:close()
return 0
end
Python decryption:
def decrypt_box():
with open("encrypted_file.companybox", 'rb') as f:
header = f.read(16) # We use this for internal info
senderPubKey = f.read(32)
cyphertext = f.read()
f.close()
# Import the secret key for use in the decryption
imported_private_key = nacl.public.PrivateKey(BOB_SECRET_KEY)
# Import the public key we just found in the file
imported_public_key = nacl.public.PublicKey(senderPubKey)
# Make a box with the 2 keys
plain_box = Box(imported_private_key, imported_public_key)
# Pass the remaining text (that includes the Nonce and MAC) to decode
plain = plain_box.decrypt(cyphertext)
print(plain.decode('utf-8'))
Previous response:
So far as I can tell, no, TweetNaCl and PyNaCl are not compatible. My group is attempting to encrypt a file with c# TweetNaCl and decrypt with python, and I always end up with a general nacl.exceptions.CryptoError: An error occurred trying to decrypt the message.
If you / someone else figures out a solution, I'd love to hear it!

How to encrypt JWT payload javascript and decrypt in Ruby

I am trying to encrypt a JWT payload in javascript and then decrypt it in my Ruby app. I found a simple Ruby encryption/decryption tool, but I do not know how to do the encryption side in javascript. Is there a way to accomplish this encryption in javascript so that my Ruby backend can decrypt it?
def encrypt(key)
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
cipher.key = Digest::SHA1.hexdigest key
s = cipher.update(self) + cipher.final
s.unpack('H*')[0].upcase
end
def decrypt(key)
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').decrypt
cipher.key = Digest::SHA1.hexdigest key
s = [self].pack("H*").unpack("C*").pack("c*")
cipher.update(s) + cipher.final
end
puts plain = 'confidential' # confidential
puts key = 'secret' # secret
puts cipher = plain.encrypt(key) # 5C6D4C5FAFFCF09F271E01C5A132BE89
puts cipher.decrypt('guess') # raises OpenSSL::Cipher::CipherError
puts cipher.decrypt(key) # confidential
Do not reinvent the wheel. There is standard for that: encrypted JWT (JWE) => RFC7516.
Moreover and as mentioned by Holger Just, you should follow the Best Current Practices and avoid unsecured algorithms.
https://jwt.io/ lists a lot of libraries that can offer more than the usual signed tokens (JWS). Unfortunately, at that time no Ruby library support JWE.

Fail to verify RSA signature on server side that was created using Javascript on client side

I'm using forge on the client where I create the signature as follows.
//Client Side
var md = forge.md.sha256.create();
md.update(encryptedVote, 'utf8');
var pss = forge.pss.create({
md: forge.md.sha256.create(),
mgf: forge.mgf.mgf1.create(forge.md.sha256.create()),
saltLength: 20
});
var signature = privateKey.sign(md, pss);
Then later on the server I try to verify the signature using the cryptography library as follows.
#server side
user_public_key_loaded.verify(
signature,
enc_encrypted_vote,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=20
),
hashes.SHA256()
)
I get consistently an Invalid signature error. I tried changing the encoding on the client to md.update(encryptedVote, 'latin1'); and now sometimes works some others it doesn't.
Any idea what I'm doing wrong?
I found hy sometimes it worked an sometimes it didn't. before verifying I was putting the JSON data into a list by doing my_list = list(my_dict.values()). And accessing the signature and vote by doing my_list[0] and my_list[1]. Apparently the order of the data in the list is random and changes from time to time. Thus the signature and vote were switching place in my function and sometimes it worked some others it didn't.

How to encrypt data in browser with JavaScript and decrypt on server side with Node.js

I'm trying to encrypt a message using AES256 on the browser, send it to the server, and then decrypt it but I keep getting this error server-side :
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
I tried for hours to find a solution but I don't see where is the issue. I'm using crypto-js for client-side and the standard library for Node.js crypto
This is the code sample that I'm using on client-side.
import * as CryptoJS from 'crypto-js';
const secret = 'example';
const passphrase = 'secret-passphrase'
const encrypted = CryptoJS.AES.encrypt(secret, passphrase);
const encrypted64 = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
// make a request to a Node.js API with the password encrypted
This is the code sample that I'm using on server-side.
const crypto = require('crypto');
const secret = req.body.secret;
const passphrase = 'secret-passphrase'
const decipher = crypto.createDecipher('aes256', passphrase);
let decrypted = decipher.update(secret, 'base64', 'utf8');
decrypted += decipher.final('utf8');
Any idea?
Thanks.
Using HTTPS will encrypt the payload during the transfer and have it decrypted at the server. HTTPS uses RSA to encrypt the keys used in the encryption of the message.
RSA uses 1024 bit key value which is difficult to crack. The hacker has to factor large numbers into their original prime values to get the keys which makes its almost impossible to crack.
It is generally advisable to use HTTPS in your transmissions.
The error generally occurs when you use the wrong key.
You are using different packages to begin with.
crypto-js will take your passphrase, create a key and encrypt cleartext that you have in secret.
crypto will do the same when you create Decipher, but then there's the issue of padding. In short, key is not same for crypto when decrypting.
Use a 32 bytes key like abcabcabc1abcabcabc1abcabcabc132
Go for client-side encryption like:
var ciphertext= C.AES.encrypt(secret, C.enc.Hex.parse(passphrase), { mode: C.mode.ECB, padding: C.pad.NoPadding }).ciphertext.toString();
And on your server side code go for following (after passing the same passphrase to decipher):
let decrypted = decipher.update(ciphertext, 'hex', 'utf8');
Give it a try. It should work. It will be easier if you use crypto-js on both client and server.
Hope it helps!

Categories