Search code examples
c#c++asp.net-coreencryptioncrypto++

C ++ (crypto ++) and C # encryption matching


For secure communication between client and server, I want to encrypt and decrypt data from both the client and the server, but I cannot get the same results, the data that comes from the client to the server is not decrypted, also when encrypting the same the same data from the server, I get a distinctive result from encryption on the client.

The client is written in C ++ using Crypto ++. The code:

string data = "teststring,teststring,teststring";
string encryptedData = client.encrypt(userData, "01234567891234560123456789123456", "0123456789123456");
string Client::encrypt(const string& str_in, const string& key, const string& iv)
{
    try {
        string str_out;
 
        AES::Encryption aesEncryption((byte*)key.c_str(), key.length());
        CBC_Mode_ExternalCipher::Encryption encryption(aesEncryption, (byte*)iv.c_str());
 
        StringSource encryptor(str_in, true,
            new StreamTransformationFilter(encryption,
                new Base64Encoder(
                    new StringSink(str_out),
                    false
                )
            )
        );
        return str_out;
    }
    catch (exception e) {
        return "null";
    }
}
string Client::decrypt(const string& str_in, const string& key, const string& iv)
{
    try {
        string str_out;
        CBC_Mode<AES>::Decryption decryption((byte*)key.c_str(), key.length(), (byte*)iv.c_str());
 
        StringSource decryptor(str_in, true,
            new Base64Decoder(
                new StreamTransformationFilter(decryption,
                    new StringSink(str_out)
                )
            )
        );
 
        return str_out;
    }
    catch (exception e) {
        return "null";
    }
}

Gives the following output:

data: "teststring,teststring,teststring"
encryptedData: "STpuD/dRgYard+Yqpdd5KOYET7607i7ZRUoKm5eshHzR3ErafaxgZ2+T1tSp0lWJ"

The server side of the code is written in C # (ASP.NET Core 3.1):

public static string Encrypt(string input)
{
    byte[] clearBytes = Encoding.Default.GetBytes(input);
 
    using (Aes encryptor = Aes.Create("AES"))
    {
        // encryptor.BlockSize = 32;
        encryptor.Padding = PaddingMode.Zeros;
        encryptor.KeySize = 128;
        encryptor.Mode = CipherMode.CBC;
        encryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789123456");
        encryptor.IV = Encoding.Default.GetBytes("0123456789123456");
        using (MemoryStream ms = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearBytes, 0, clearBytes.Length);
                cs.Close();
            }
            byte[] bt = ms.ToArray();
            input = Convert.ToBase64String(bt);
        }
    }
    return input;
}
 
public static string Decrypt(string input)
{
    byte[] clearBytes = Encoding.ASCII.GetBytes(input);
 
    using (Aes decryptor = Aes.Create("AES"))
    {
        //decryptor.BlockSize = 32;
        decryptor.Padding = PaddingMode.Zeros;
        decryptor.KeySize = 128;
        decryptor.Mode = CipherMode.CBC;
        decryptor.Key = Encoding.ASCII.GetBytes("01234567891234560123456789123456");
        decryptor.IV = Encoding.ASCII.GetBytes("0123456789123456");
        using (MemoryStream ms = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(ms, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
            {
                cs.Write(clearBytes, 0, clearBytes.Length);
                cs.Close();
            }
            byte[] bt = ms.ToArray();
            input = Encoding.ASCII.GetString(bt);
        }
    }
    return input;
}

Output:

data: "teststring,teststring,teststring"
encryptedData: "tIDlWnnzOQWh5HIvRDJya6z7jOglkIlYrICeYW9RoEM="

I cannot decrypt data from both the client and the server. Help me please.


Solution

  • The posted C++ code is fine. It returns the posted ciphertext STpu...0lWJ on my machine and the ciphertext can be decrypted with the decrypt() method.

    In contrast, although the posted C# code returns the posted ciphertext tIDl...RoEM=, the ciphertext cannot be decrypted using the Decrypt() method. This has two reasons:

    • In the Encrypt() and in the Decrypt() method different keys are used. The key of the Decrypt() method matches the key applied in the C++ code. With regard to a comparison of the ciphertexts of both codes, the key in the Encrypt() method should be replaced.
    • The ciphertext is Base64 encoded in the Encrypt() method, but not Base64 decoded in the Decrypt() method (but ASCII encoded instead). Here a Base64 decoding must be done in the Decrypt() method (note that an ASCII decoding in the Encrypt() method is not an alternative, since this would corrupt the ciphertext).

    If these two bugs are fixed, the ciphertexts of C++ and C# code match except for the end. This last mismatch is caused by different paddings. In the C++ code PKCS7 padding is used, in the C# code Zero padding. If the padding in the C# code (in the Encrypt() and Decrypt() methods) is changed to PaddingMode.PKCS7, the ciphertexts match.

    Other problems in the C# code are:

    • In the Encrypt() method Encoding.Default is used, in the Decrypt() method Encoding.ASCII. Here a consistent encoding, e.g. Encoding.UTF8 should be applied.
    • The specified 128-bit key size is not consistent with the 256-bit key used. This has no effect because the explicit key specification automatically corrects the key size (nevertheless, the key size should be specified correctly or completely omitted).

    Also, it should be noted that a static IV is insecure (for testing purposes, of course, that's OK).