N
N
Nikolai Mokhov2015-10-05 22:15:22
.NET
Nikolai Mokhov, 2015-10-05 22:15:22

How to correctly transfer the salt from the client to the server and back when encrypting?

As a server I use ASP.NET WebApi 2.
As a client, a universal application on Windows 10.
NET.Framework 4.6 is used everywhere
. Data is sent via http.
For encryption I use PCLCrypto
https://github.com/aarnott/pclcrypto
Below is the class for encryption:

public static class Crypto
    {
        public static byte[] CreateSalt(uint lengthInBytes)
        {
            return WinRTCrypto.CryptographicBuffer.GenerateRandom(lengthInBytes);
        }

        public static byte[] CreateDerivedKey(string password, byte[] salt, int keyLengthInBytes = 32, int iterations = 10000)
        {
            byte[] key = NetFxCrypto.DeriveBytes.GetBytes(password, salt, iterations, keyLengthInBytes);
            return key;
        }
        
        public static byte[] EncryptAes(string data, string password, byte[] salt)
        {
            byte[] key = CreateDerivedKey(password, salt);

            ISymmetricKeyAlgorithmProvider aes = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesEcbPkcs7);
            ICryptographicKey symetricKey = aes.CreateSymmetricKey(key);
            var bytes = WinRTCrypto.CryptographicEngine.Encrypt(symetricKey, Encoding.UTF8.GetBytes(data));
            return bytes;
        }

        public static string DecryptAes(byte[] data, string password, byte[] salt)
        {
            byte[] key = CreateDerivedKey(password, salt);

            ISymmetricKeyAlgorithmProvider aes = WinRTCrypto.SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesEcbPkcs7);
            ICryptographicKey symetricKey = aes.CreateSymmetricKey(key);
            var bytes = WinRTCrypto.CryptographicEngine.Decrypt(symetricKey, data);
            return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
        }
    }

I encrypt the username and password on the client before sending:
var salt = Crypto.CreateSalt(16);
            var bytes = Crypto.EncryptAes(data, pass, salt);

I decrypt on the server:
var str = Crypto.DecryptAes(bytes, pass, salt);
When I tested in one application, everything worked. As soon as I spread the parts to the server and the client, then there were difficulties when converting byte[] to string and back. used Convert.ToString() and Encoding.UTF8.GetBytes/GetString. Using these functions results in different values ​​in the byte array.
Found this example:
stackoverflow.com/questions/472906/converting-a-st...
Used the first answer:
static byte[] GetBytes(string str)
        {
            var bytes = new byte[str.Length * sizeof(char)];
            Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
            return bytes;
        }

        static string GetString(byte[] bytes)
        {
            var chars = new char[bytes.Length / sizeof(char)];
            Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
            return new string(chars);
        }

Works on one machine. But in the comments to this answer, something is said that this method will only work on one machine. There is no possibility to check on different machines.
I know about SSL, but I will not use it yet.
The salt is passed along with the ciphertext, so it is generated each time it is encrypted. It seems that this (new generation of salt) increases the chances of being hacked by brute force on rainbow tables or something like that.
Please tell me, within the same version of net.framework, but on different devices, will this code work? Whether correctly there will be transformations with lines? And maybe there are more universal solutions?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Artem Dudnik, 2015-10-15
@Kolay_Net

The comment correctly says that the result may depend on the type of client / server architecture, and specifically on the byte
order You can check the byte order using BitConverter.IsLittleEndian
As for the idea itself, that is, standard for platform-independent serialization / deserialization of binary data: Base64 , ProtoBuf , BSON , etc.
In your case, it is better to use Base64, because it's fairly common, simple, and doesn't require additional dependencies. Look at the Convert.ToBase64String and Convert.FromBase64String methods

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question