I'm coding(in C#) an offline(no network or server), hybrid file encryption app, implementing Inferno's ECIES. The user's private key is to be stored either on the pc drive or on a usb key, after being encrypted with a key(password) hashed with ~ 1 million Scrypt iterations. The user can load his key into protected memory once the app is started. Loading the key takes a huge 20 seconds but it would be a one-time/session delay if the following is acceptable:
For files meant to be kept by the user(some are sent, some are kept), is it secure to produce a "shared" symmetric key with the user's own public key? This would allow the user to have one password to remember(instead of one for each symmetric and asymmetric key) and since the symmetric key produced this way has a high entropy, hashing iterations are not necessary when saving/loading files, something that happens very often during a session.
The code itself is working but that does not tell me if the approach is secure. Just to make sure I'm clear, here is a shortened code example:
internal static void SendText(string text, byte[] ephemeralPublicBlob, string file)
{
CngKey receiverKey = ephemeralPublicBlob.ToPublicKeyFromBlob();
var ephemeralBundle = receiverKey.GetSharedEphemeralDhmSecret();
var ephemeralPublic = ephemeralBundle.EphemeralDhmPublicKeyBlob;
var ephemeralSymmetric = ephemeralBundle.SharedSecret;
var textSegment = new ArraySegment<byte>(text.ToBytes());
var ciphertext = SuiteB.Encrypt(ephemeralSymmetric, textSegment);
using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write))
{
byte[] sent = Utils.Combine(ephemeralPublic, ciphertext);
fs.Write(sent, 0, sent.Length);
}
}
internal static string ReceiveText(string file, CngKey masterKey)
{
string decrypted = null;
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
{
byte[] received = new byte[fs.Length];
fs.Read(received, 0, (int)fs.Length);
var ephemeralPublic = new ArraySegment<byte>(received, 0, 104);
var cipherText = new ArraySegment<byte>(received, 104, received.Length - 104);
var sharedSecret = masterKey.GetSharedDhmSecret(ephemeralPublic.ToArray().ToPublicKeyFromBlob());
decrypted = SuiteB.Decrypt(sharedSecret, cipherText).FromBytes();
}
return decrypted;
}
So, in the first function(SendText), if I pass the sender's(instead of receiver's) public blob as the byte[] argument, the code works, but am I leaking/messing something?