how to encrypt the chat message with multiple people public key together and restore the message? - cryptography

I have a application with two users and one middle man, all of them holding the private and public key, To make the secured chat, two users and one middle man are all sending the public key and generate a secured channel. After establishing the channel, the middle man doesn't have the ability to see the encrypted message unless one of the user is sending his own key to the middle man.
i am not very familiar with cryptography, so for this app i know how to encrypt and decrypt the message.
encrypt(data) {
try {
var cipher = Crypto.createCipher('aes-256-cbc', this.password);
var encrypted = Buffer.concat([cipher.update(new Buffer(JSON.stringify(data), "utf8")), cipher.final()]);
FileSystem.writeFileSync(this.filePath, encrypted);
return { message: "Encrypted!" };
} catch (exception) {
throw new Error(exception.message);
}
}
but I don't know how to establish the encrypted channel from the stakeholders' key, and how can the one middle to see the message using his key and one of users' key?
is there a way to accomplish this using the cryptography?

I'm not sure I completely understand, but I think if you want to go with a system that doesn't use public key crypto I would suggest a system using 2 stages of encryption, actually a lot like PGP only both stages use symmetric keys-
1) There is a fixed session key generated by the first person in the chat, this can be a randomly generated number.
2) This session key is then encrypted by the keys belonging to every new member of the chat group and individually sent to them.
3) The new members decrypt with their own unique keys to get the plaintext session key back.
4) This session key is subsequently used to decrypt the messages sent to all participants. The same key can also be used to encrypt and send any new messages from any entitled participant(i.e. has the valid session key) on the chat group.
This is used in some systems but it relies on the unique keys being securely transmitted, in the first instance. If this condition can't be met, it's a problem that can be solved with public key crypto to build an end-to-end secure message system like PGP, whatsapp, etc.

Related

How to use a private key that is stored on an HSM that is secured by a user password via Pkcs11Interop OR CNG?

Summary
Use CNG or Pkcs11Interop or any other alternatives to login to an HSM, search for a privatekey then pass it on to a 3rd party application for use.
The key cannot be extracted from the HSM or stored in memory.
a 3rd Party application needs to make use of a private key that is stored on a Hardware Security Module (HSM).
I have looked into two methods CNG and Pkcs11Interop.
The code needs to accomplish the following:
1-Authenticate and establish a session with the HSM
2-Search for the key
3-Pass the private key to the 3rd party using RSACryptoServiceProvider or other methods.
Important: The key cannot be accessed extracted from the HSM or access directly (by design for security purposes).
Below are the two samples I've put together for both CNG and PKCS11Interop
The Problem:
1-CNG I am struggling to authenticate (if that's possible)
2-PKCS11Interop I've been able to login, search for the key but struggling to make use of the key.
Happy to use either of the methods, and I welcome any assistance, alternative solutions or advice.
CNG Code:
This code works when authentication is disabled on HSM
Q. Is there a way to authenticate using a password , open a session prior to using the key?
CngProvider provider = new CngProvider("CNGProvider");
const string KeyName = "somekey";
key = CngKey.Open(KeyName, provider);
Console.WriteLine("found the key!");
var cngRsa = new RSACng(key);
var privateSshKey = new SshPrivateKey(cngRsa);
PKCS11Interop, I managed to authenticate, search for the key and assign it to a handle..
Q. How do i go about passing the private key onto a standard .Net Framework type AsymmetricAlgorithm? while keeping in mind it not exportable?
can it be passed to RSACryptoServiceProvider? and then onto AsymmetricAlgorithm?
using (IPkcs11Library pkcs11Library = Settings.Factories.Pkcs11LibraryFactory.LoadPkcs11Library(Settings.Factories, Settings.Pkcs11LibraryPath, Settings.AppType))
{
ISlot slot = Helpers.GetUsableSlot(pkcs11Library);
using (ISession session = slot.OpenSession(SessionType.ReadWrite))
{
//search for key
try
{
const string keyname = "somekey";
// Login as normal user
session.Login(CKU.CKU_USER, Settings.NormalUserPin);
IObjectHandle publicKeyHandle = Helpers.CreateDataObject(session);
IObjectHandle privateKeyHandle = Helpers.CreateDataObject(session);
// Prepare attribute template that defines search criteria
List<IObjectAttribute> privateKeyAttributes = new List<IObjectAttribute>();
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_RSA));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, keyname));
List<IObjectHandle> foundPrivateKeys = session.FindAllObjects(privateKeyAttributes);
if (foundPrivateKeys == null || foundPrivateKeys.Count != 1)
throw new Exception("Unable to find private key");
// Use found object handles
privateKeyHandle = foundPrivateKeys[0];
session.FindObjectsFinal();
// How do i go about using the privatekey handle here?
session.DestroyObject(privateKeyHandle);
session.Logout();
}
catch (Exception ex)
{
Console.WriteLine("Crypto error: " + ex.Message);
}
Console.WriteLine("done!");
System.Console.Write("[Hit Enter to Continue]");
System.Console.ReadLine();
}
}
With an HSM, by design, you cannot "Pass the private key to a 3rd party app".
You also cannot pass the key handle between processes (although this might work in some implementations - a key handle should be PKCS11 session specific).
Your 3rd party app needs to offload cryptographic operations to the HSM by using a configurable cryptography library like OpenSSL (or similar) or if it is using CNG it should allow you to configure the provider.
Q. Is there a way to authenticate using a password , open a session prior to using the key?
A.: For an app that uses CNG, you should use the CNG Key Storage Provider (KSP) from the HSM Vendor after you have configured it.
The HSM Vendor KSP will then prompt for the password or, if you configured the provider (using a utility or configuration file from the HSM vendor) to store the password/pin, it will just work.
eHSM sample code using NCryptNative:
SafeNCryptProviderHandle handle;
NCryptOpenStorageProvider(handle, "eHSM Key Storage Provider",0);
...
Q. How do i go about passing the private key onto a standard .Net Framework type AsymmetricAlgorithm? while keeping in mind it not exportable? can it be passed to RSACryptoServiceProvider? and then onto AsymmetricAlgorithm?
A.: No, you cannot pass key material and you cannot pass the raw PKCS11 handle to the CNG Framework. You either have to use the PKCS11Interop functions to perform all cryptographic operations OR you have to do everything in CNG (correctly configured as above).
To directly use the PKCS11 interface you continue calling PKCS11 functions with the key handle, ie.
// How do i go about using the privatekey handle here?
// something like this
session.SignInit(mechanism, privateKeyHandle);
session.Sign(data, signature));

WSO2 Send Recovery Notification

In our current WSO2 setup, after a user performs a self creation, we place his account into a locked state, and send a confirmation email to the address specified during creation. This email has a link which allows the user to verify his account.
For development purposes, we are attempting to get the workflow down using the UserInformationRecoveryService wsdl in SOAP UI. The service which we seem to want is called sendRecoveryNotification. Here is the signature of this service:
sendRecoveryNotification(String username, String key, String notificationType)
The username parameter is simply the username of the WSO2 user in question, which we have. For the notificationType we have been using email, which presumably would trigger an email to be sent to the user. The problem is with the key parameter. It is not clear what value should be used as key, and all our guesses always lead to this error response:
18001 invalid confirmation code for user : tbiegeleisen#abc.com#tenant.com
We also noticed that several other services also expect a key, and it is not clear how to get this value.
Can someone shed light on the workflow for user recovery in WSO2? It seems to be a Catch-22 with regard of requiring a token in order to generate a new token to be sent to a user.
The WSO2 documentation clearly spells out the workflow for recovery with notification. The key which needs to be used is the return value from a call to the verifyUser() SOAP web service. This service itself expects a Captcha which normally would be sent from the UI. Here is a code snippet showing how a recovery notification can be sent:
String cookies = client.login("admin#tenant.com#tenant.com", "admin");
UserInformationRecoveryUtil userInfoutil = new UserInformationRecoveryUtil(webserviceUrl, cookies);
CaptchaInfoBean captchaInfo = new CaptchaInfoBean();
captchaInfo.setImagePath(captchaPath);
captchaInfo.setSecretKey(captchaKey);
captchaInfo.setUserAnswer(captcha);
String username = emailId + "#" + tenantDomain;
String key = userInfoutil.verifyUser(username, captchaInfo);
// now pass the key based on the Captcha along with the type of recovery action
userInfoutil.sendRecoveryNotification(username, key, "accountUnLock");

Webapplication log in system

I am using revel to build my webapplication and trying to write authentication module.
I finished with sign up part and now heading to write sign in part.
I read about security part on The definitive guide to form-based website authentication and will use this recommendation.
What I am really do not know is, how sign in works. I am imaging that the process works like this:
User write username and password into the html form and press sign in
Server receive request and the controller will check, if user information match with data on database.
If yes, how continue.
The third point is where I am staying. But I have some idea how could works and not sure, if is the right way.
So when sign in information match with the database, I would set in session object(hash datatype) key value pair signed_in: true. Everytime when the user make a request to the webapplication, that need to be authenticated, I would look in the session object, if signed_in is true or not.
This is the way I would do, but as I mentioned above, I do not know if it is the right way.
Yes like #twotwotwo mentioned, give it the user id and also a role.
So server side rendered flow: Step 1
user sends username (or other identifier) and secret.
using scrypt or bcrypt the secret is checked against the stored salted hash in the database
if it matches you create a struct or a map
serialize struct or map into string (json, msgpack, gob)
encrypt the string with AES https://github.com/gomango/utility/blob/master/crypto.go (for instance). Set a global AES key.
create a unique cookie (or session) identifier (key)
store identifier and raw struct or map in database
send encrypted cookie out (id = encrypted_struct_or_map aka the encrypted string)
On a protected resource (or page): Step 2
read identifier from cookie
check if id exists in db
decode cookie value using AES key
compare values from cookie with stored values
if user.role == "allowed_to_access_this_resource" render page
otherwise http.ResponseWriter.WriteHeader(403) or redirect to login page
Now if you wanted you could also have an application-wide rsa key and before encrypting the cookie value sign the string with the rsa private key (in Step 1). In Step 2 decode with AES key, check if signature valid, then compare content to db stored content.
On any changes you have to update the cookie values (struct/map) and the info in the database.

How should an application authenticate with a datastore?

I'm writing an iPad game that sends hi-score type data (ie data beyond what Game Center supports) to a Google appengine datastore. It sends these updates via http GET or POST requests, such as http://myapp.appspot.com/game/hiscore/925818
Here is how I thought to ensure the appengine datastore isn't spammed with false data.
zip/encrypt the payload data using hardcoded p#ssw0rd saved in the iOS binary. Encode that binary data as base64. Pass base64 payload in the url query string or in the POST data. At handler, unbase64, then unzip data with p#ssw0rd. Follow instructions in payload to update highscore-type data.
CON: If p#ssw0rd is somehow derived from the iOS binary, this scheme can be defeated.
Is this adequate/sufficient? Is there another way to do this?
There is absolutely no way to make sure it's your client that sends the data. All you can try is to obfuscate some thing to make it harder for spammers to submit data.
However I think there are two thing you can do:
Have some kind of secrect key saved in the binary
Have a custom algorithm calculating some checksum
Maybe you can go with a combination of both. Let me give you an example:
Create some custom (complex!) alorithm like (simplyfied):
var result = ((score XOR score / 5) XOR score * 8) BITSHIFT_BY 3
Then use your static stored key with that result and a well known hash function like:
var hash = SHA256(StaticKey + result)
Then send that hash with the score to the server. The server has to "validate" the hash by performing the exact same steps (evaluate algorithm + do the SHA256 stuff) and compare the hashes. If they match the score hopefully comes from your app otherwise throw it away, it comes from a spammer.
However this is only one thing you can do. Have a look at the link from mfanto, there are many other ideas that you can look at.
Be sure to not tell anybody about how you're doing it since this is security through obscurity.
Ok me, there are 2 methods to do this.
1) Purchase an SSL certificate for $FREE.99 and open HTTPS connections only to your server to submit hiscore type data. Connection speed should be around 500 ms due to handshake roundtrip time.
2) Embed an RSA public key certificate in your iOS app, and have the RSA private key on your server.
You can then do 1 of 2 things with this second scheme:
IF your data messages are really small (≤256 B) you can just encrypt and send 256B packages (RSA payload is limited by the number of bits in the key)
ELSE IF the data is too large (>256B), generate a random symmetric key (AES), and pack:
SYMMETRIC AES KEY ENCRYPTED WITH RSA PUBLIC KEY
BINARY DATA ENCODED WITH SYMMETRIC AES KEY
The server then takes the first 256 bytes and decodes it, then the server uses that AES key to decrypt the rest of the message.
The above 2 only prevent eavesdropping, but it means the data format of your messages is hidden. At some level, it is still a type of security by obscurity, since if the hacker has your public key AND your message format, they can manufacture messages.

Developing a Service with API Keys (starting point)

Looked on google and couldn't find anything.
Any good resources to get started designing my backend for a RESTless webapp thats going to rely heavily on API keys.
I know how to write restless webservices etc, just never used API-keys. Generally do people just generate guids for users etc?
Here's how I'm creating API keys for a web service:
string CreateApiKey(int length)
{
var bytes = new byte[length * 2];
using (var rng = new RNGCryptoServiceProvider())
rng.GetBytes(bytes);
var chars = Convert.ToBase64String(bytes)
.Where(char.IsLetterOrDigit)
.Take(length)
.ToArray();
var key = new String(chars);
return key;
}
GUID's are typically not "random" enough and can be easily guessed by the bad-guys.
Take some "random" data like the user's password hash, some random numbers and run the result through sha1 or a similar hash function.
If you want one API key per account, simply add it to the account metadata table. Otherwise use a table linked to the accountIds to store the api keys.
Server side use a cache using the api-key as the key to store temporarily the account metadata so you only need to go to the db once per session.
And of course everything must go over https to avoid that the API key be stolen.
Now if your service is "session" oriented you can consider using a temporary session key so you do not need to expose the API key. Look for public key encryption to investigate this further.