Preventing Pubnub cipher key from being viewed - javascript

To enable message-level encrpytion in Pubnub, one would include the cipher key when instantiating PubNub on the client.
var pubnub = PUBNUB({
publish_key: 'my_pubkey',
subscribe_key: 'my_subkey',
cipher_key: 'my_cipherkey'
});
The PubNub docs then state:
Never let your cipher key be discovered, and be sure to only exchange it / deliver it securely. On JavaScript, this means explicitly don't allow anyone to View Source or View Generated Source or Debug to enable viewing your cipher key.
Exactly how would one completely obfuscate a cipher key in a web page? It is not possible to completely prevent someone from viewing the source, only make it inconvenient. Any encryption/decryption routines on the client can also be identified fairly easily.
What exactly is the suggested route we should take here?

I am not familiar with pubnub, but in cases similar to this, you can create a hash or some other reference that points to the secret on your server. So the hash is shared between client/server, and the server references the hash as your key.
You have not said what your server side language is, but there are a number of different hashing mechanisms available, SHA-1 or similar is recommended https://en.wikipedia.org/wiki/SHA-1

That's exactly the point: you cannot ever publish your cipher_key on the web under any circumstances. Websites may use their API given the other (public) keys, but the cipher_key must only be used from environments that are secure.

Related

Producing the same signature with WebAuthn

I just started playing around with WebAuthn on localhost. I was given to understand that the signature value found in credentials.response.signature was signing credentials.response.clientDataJSON. However, for the same inputs / challenge for navigator.credentials.get I seem to be getting a different signature. My best guess is there is a timestamp or counter going somewhere into the value that is signed?
I can't seem to decode the signature or authenticatorData, which would really help me to visualize what's going on inside. I'm able to decode clientDataJSON as follows, anyone have sample code with which I code decode the other two aforementioned params?
String.fromCharCode.apply(null, new Uint8Array(credentials.response.clientDataJSON))
I also found when decoding clientDataJSON I get the occasional extra field in Chrome, which is a little annoying for my use case.
My goal is to get the user to produce the same signature or hash each time when authenticating the same PublicKeyCredential. Is there a way to do this? or are there other methods within the scrope of WebAuthn or outside of its scope to benefit from the biometric auth with which I can produce identical signatures or hashes from the same inputs?
Please forgive any misconceptions I might have about WebAuthn, I'm quite new to this amazing tech. I completely understand that this is not the original intended use of WebAuthn so a janky workaround may be needed.
My goal is to get the user to produce the same signature or hash each time when authenticating the same PublicKeyCredential.
This is actually a really bad idea. The whole purpose of signing a message with a random challenge is to avoid replay attacks. Otherwise, if an attacker somehow intercepts an authentication message, that message could simply be reused to impersonate the user.
I was given to understand that the signature value found in credentials.response.signature was signing credentials.response.clientDataJSON
That is not accurate. The signature signs authenticatorData + SHA256(clientDataJSON).
Both are variable. The authenticatorData contains a "counter" increasing each time the credential key was used to authenticate and clientDataJSON should (or must to be secure) contain a randomly server side generated challenge.
I can't seem to decode the signature or authenticatorData, which would really help me to visualize what's going on inside. I'm able to decode clientDataJSON as follows, anyone have sample code with which I code decode the other two aforementioned params?
The signature cannot be "decoded", it can only be "verified" given the adequate public key. For the other paramters authenticatorData and clientDataJSON , check out the following link at the bottom, it will decode them.
https://webauthn.passwordless.id/demos/playground.html
I also found when decoding clientDataJSON I get the occasional extra field in Chrome, which is a little annoying for my use case.
I'm not sure, I believe this is related to localhost testing.
If you want a small, fixed bit of data associated with a credential then you may wish to investigate the credBlob or prf extensions. Not all authenticators will support them, however. Many more will support prf but support for that in Chromium won't appear for a few more months. So there's not a great answer here yet, but it may work better than trying to fix the signature.
So, first things first, in general it depends on the signature scheme used whether the same signature will be produced when you use the same data as input. Check this question https://crypto.stackexchange.com/questions/26974/ where they discuss about it.
Now, coming back to WebAuthn (assuming that you use a signature algorithm that for the the same input will generate the same signature) let's look how the signature is generated. Here is a small code from my virtual authenticator that is responsible for generating the WebAuthn signature:
let authData = this._concatUint8Arrays(
rp_id_hash,
flags,
sign_count, // The signature counter will always increase
this._getAAGUID(),
credential_id_length,
credential_id,
cose_key
);
// Attestation object
let attestation_object = {'fmt': 'none', 'attStmt': {}, 'authData': authData};
// ...
// Generate signature
let client_data_hash = new Uint8Array(await crypto.subtle.digest('SHA-256', client_data));
let signatureData = this._concatUint8Arrays(authData, client_data_hash);
let signature = await Algorithms.Sign(this.private_key, signatureData);
You will notice that the data to be signed include the authenticator's signature counter which should increase each time you use the authenticator. This helps detecting replay attacks or cloned authenticator attacks (more info here).
Thus, it is not feasible to generate the same signature.
If you want to look more into what is going on under the hood of WebAuthn you can have a look into my WebDevAuthn project and browser extension that allows you to inspect the WebAuthn requests and responses.

Is it possible to encrypt (not hash!) and use a salt?

I am encrypting objects using Node.js native crypto methods like createCipherIv.
const algorithm = "aes256";
const inputEncoding = "utf8";
const outputEncoding = "hex";
const iv = randomBytes(16);
export async function encryptObject(dataToEncrypt: object, key: Buffer) {
const clear = JSON.stringify(dataToEncrypt);
const cipher = createCipheriv(algorithm, key, iv);
let ciphered = cipher.update(clear, inputEncoding, outputEncoding);
ciphered += cipher.final(outputEncoding);
return iv.toString(outputEncoding) + ":" + ciphered;
}
Sometimes I am encrypting the same object multiple times and send it over http(s). That makes me think a man in the middle could observe that communication and maybe gain information about my user by using something like a Rainbow table to map the encrypted Data to real data over time.
Now I'm not sure if my worries make sense, but I'm thinking, that my encryption could be more secure if a add a salt to it. So far I've only come accross salt when hashing, not encrypting. Hashing is not an option for me, because I cannot rely on hashes to be equivalent. I actually have to do something with the data, so I have to be able to decrypt it again.
So my questions are:
Do my thoughts add up, and I would be better of adding salt?
Is it possible to use Node.js native crypto functions for symmetric encryption while adding salt to the mechanism in order to have different encrypted results on every run?
Basically the IV is your salt. That's it purpose (apart from initializing the chaining algorithm). So you are ok with the code you posted here. Initialization vector is random so the encrypted bytes will be different every time.
Just check it with the simple console.log you will see that resulting bytes are totally different every time.
On the other hand I don't think that this (identical encrypted bytes) is much of a concern here. I would make rather sure that the chaining method is at least CBC. Here you can read more about it:
https://en.m.wikipedia.org/wiki/Block_cipher_mode_of_operation
Also if you want to be super secure with the man in the middle attack. You can add some HMAC to your message. This will ensure that no one can flip a bit in your message to make it different. In other words it provides
data integrity and authenticity of a message.
But still if you send data over httpS, all of those safety measures are already in place. Hence the name of the examplary https cipher:
tls_dhe_rsa_with_aes_256_gcm_sha384. Extracting the things that I mentioned here. It uses aes256 with gcm chaining mode and sha348 as a hashing method for the hmac.

Obfuscating the Crypto.JS passphrase?

I am using Crypto.js in a project, I would like to be able to protect the password by obfuscating it, can this be done with crypto.js?
On Node.JS
You'd be better off to consider the password a config variable and treat it the same way you treat your other sensitive info - the DB connection info for example.
I like this tutorial which shows how you can get different config values for different environments that your node app runs in.
CryptoJS is an encryption library. You can certainly store an encrypted passphrase and the key that was used to encrypt the passphrase beside it. I would call that obfuscation. It's a very weak type of obfuscation, but it is one.

node authentication model / scheme

(xposted from nodejs#googlegroups.com)
what's the best locally stored authentication scheme?
i've found a few:
http://dailyjs.com/2011/01/10/node-tutorial-9/
github.com/ncb000gt/node.bcrypt.js/tree/master/examples
github.com/Turbo87/locomotive-passport-boilerplate/blob/master/app/models/account.js
(which looks like it came from the bcrypt example)
it looks like mongoose-auth implement from bcrypt's example as well:
github.com/bnoguchi/mongoose-auth/blob/master/lib/modules/password/plugin.js
and, i can't figure out how everyauth is generating passwords.
github.com/bnoguchi/everyauth/blob/master/lib/modules/password.js
... and i've found tons that generate based on Math.random(Date.now *
some_number).... something like that - didn't look right so i don't
exactly remember.
what's the best method for doing this security wise?
Locally storing authenticated credentials is one of the worst possible ways to authenticate clients. In order to pull this off you need to use cryptography, which introduces the possibility of brute force. A good example of how this goes horribly wrong is the Oracle Padding Attack used against .Net.
If you want a secure system you won't implement this. If you want something that isn't very secure but probably will work then you should use an HMAC. Bcrypt, block ciphers, and stream ciphers are really not the right choice. You can implement an HMAC with bcrypt, but i would choose another hash function like sha256.
Also, the current date time is NOT A RANDOM VALUE, this should never be relayed upon for the calculation for a random value. You will need to keep track of the time so that the session token can expire. Your secret should be generated with an entropy store like /dev/random

Using <keygen> to get an RSA key for use with javascript?

I need an RSA key pair for my web project and while there are some libraries I think it would be a good idea to rely on the browser (for security and speed) to generate the key for me. Is it possible to use keygen or something an other browser API to do so? I don't know how to get the keys from keygen. They seem to be generated on submit, but I don't want to send them to the server.
What you are probably looking for is something like Mozilla's DOMCrypt API proposal. It allows you to generate a key pair via window.mozCrypto.pk.generateKeypair() (window.mozCrypto is supposed to change into window.crypto later), you can get the public key and also encrypt or decrypt text with the private key. It will still not grant you direct access to the private key however, you only get a key ID.
Unfortunately, this API isn't supported by any browser yet. There is only a Firefox extension that can be used to test it, so that proposal is still in a very early stage. But I think that's the best you can get at this point.
I found this site, talking about generating RSA keys within the browser
There is a SSL-like protocol implemented in JavaScript : aSSL.
It uses a RSA algorithm for cryptography you could use their Keys generator.
Let's just say this is a scary idea due to the possibility of injecting code that steals the private key.

Categories