从 C++ (crypto++) 到 C# 的匹配加密

HOC*_*C13 5 c# c++ encryption

我正在尝试使用 crypto++ 和 c# 在 c++ 上匹配加密方案,但似乎无法在两者上获得相同的结果。他们都对自己工作,但不是从一个到另一个。任何帮助都会很棒!

使用 Crypto++ 的 C++ 代码:

std::string key = "01286567891233460123456789123456";
std::string iv = "0123456789123456";

std::string encrypt(const std::string& str_in)
{
    std::string str_out;

    CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());

    StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
    stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);
    stfEncryptor.MessageEnd();

    return str_out;
}
std::string decrypt(const std::string& cipher_text)
{
    std::string str_out;
    CryptoPP::AES::Decryption aesDecryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, (byte*)iv.c_str());

    CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(str_out));
    stfDecryptor.Put(reinterpret_cast<const unsigned char*>(cipher_text.c_str()), cipher_text.size());
    stfDecryptor.MessageEnd();

    return str_out;
}
Run Code Online (Sandbox Code Playgroud)

代码跑:

 std::string str = encrypt("123456789012345");
 str = decrypt(str);
Run Code Online (Sandbox Code Playgroud)

这个输出是:

 Encrypted: Ö&qcƒ“¹yLY»Lïv¹w“¼LLŠÀ¶ó¢,óð9·
 Length: 32
 Decrypted: 123456789012345
 Length: 16
Run Code Online (Sandbox Code Playgroud)

现在在 C# 中,我有以下代码:

 public string Encrypt(string clearText)
 {
       byte[] clearBytes = Encoding.Default.GetBytes(clearText);

       using (Aes encryptor = Aes.Create("AES"))
       {
           // encryptor.BlockSize = 128;
            encryptor.Padding = PaddingMode.Zeros;
            encryptor.KeySize = 128;
            encryptor.Mode = CipherMode.CBC;
            encryptor.Key = Encoding.Default.GetBytes("01234567891234560123456789123456");
            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();
                clearText = Encoding.Default.GetString(bt);// Convert.ToBase64String(bt);
            }
        }
        return clearText; //Return the encrypted command
  }

 public string Decrypt(string cipherText)
 {
       byte[] clearBytes = Encoding.Default.GetBytes(cipherText);

        using (Aes decryptor = Aes.Create("AES"))
        {
              // decryptor.BlockSize = 128;
                decryptor.Padding = PaddingMode.Zeros;
                decryptor.KeySize = 128;
                decryptor.Mode = CipherMode.CBC;
                decryptor.Key = Encoding.Default.GetBytes("01286567891233460123456789123456");
                decryptor.IV = Encoding.Default.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();
                    cipherText = Encoding.Default.GetString(bt);// Convert.ToBase64String(bt);
                }
         }

         return cipherText; //Return the decrypted text
     }
}
Run Code Online (Sandbox Code Playgroud)

代码运行:

string orig = "123456789012345";
string cipher = Encrypt(orig);
string dedata = Decrypt(cipher);
Run Code Online (Sandbox Code Playgroud)

结果是:

Orig: 123456789012345
Encrypted: êßyoº0¦ëì›X˜Ü
Length: 16
Decrypted: 123456789012345 
Length: 16
Run Code Online (Sandbox Code Playgroud)

如您所见,加密的字符串最终会有所不同。因此,当我在 c++ 中获取加密字符串时,它无法在 c# 中解密它,如下所示:

bytes[] encryptedText = ENCRYPTED TEXT FROM C++
text = System.Text.Encoding.Default.GetString(encryptedText);
text = Decrypt(text);
Run Code Online (Sandbox Code Playgroud)

C++ 为它的加密字符串返回 32 个字节,我相信这是添加的填充。不确定如何在 c# 代码中复制它,反之亦然以匹配事物。不知道这里是否还有我遗漏的东西......感谢您的帮助!

编辑:

我已经匹配了键,现在除了填充差异外,字符串两端都匹配。当我尝试在 C# 中解密字符串时,它告诉我输入数据不是正确的块大小?现在有什么帮助吗?

再次编辑:

它似乎为每个 c# 和 c++ 加密函数生成相同的字节字符串,因此问题解决了。我现在似乎遇到的问题是在 c# 方面,我接收加密的字符串并使用以下方法转换字节: text = System.Text.Encoding.Default.GetString(recvBuf); recvBuf 是来自 c++ 的加密字符串,它缺少字符串的最后一个字符。它与减去最后一个字符的 c++ 字符串匹配??不知道为什么会这样。

例如,我的 c++ 发送了这个加密的字符串:Ö&qcƒ“¹yLY»Lïv,而我的 c# 程序只会收到这个:Ö&qcƒ“¹yLY»Lï,这反过来会使其解密失败。如果有任何区别,加密的字符串将通过 TCP SOCKET 发送。

编辑

将两端的编码和解码更改为 base64 后仍然缺少字节。

C++ 1iZxY4OTHrl5TFm7Gkzvdrl3k7xMTIrAtvOiLPPwObc=
C# 1iZxY4OTHrl5TFm7Gkzvdg==
C# RECEIVED 1iZxY4OTHrl5TFm
Run Code Online (Sandbox Code Playgroud)

新代码 C#:

    public string Encrypt(string clearText)
    {
        byte[] clearBytes = Encoding.Default.GetBytes(clearText);

        using (Aes encryptor = Aes.Create("AES"))
        {
           // encryptor.BlockSize = 128;
            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();
                clearText =  Convert.ToBase64String(bt);
            }
        }
        return clearText; //Return the encrypted command
    }
Run Code Online (Sandbox Code Playgroud)

和 C++ 代码:

std::string encrypt(const std::string& str_in)
{
    std::string str_out;
    std::string str_out2;

    CryptoPP::AES::Encryption aesEncryption((byte*)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (byte*)iv.c_str());

    StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(str_out));
    stfEncryptor.Put(reinterpret_cast<const unsigned char*>(str_in.c_str()), str_in.length() + 1);
    stfEncryptor.MessageEnd();

    str_out2 = base64_encode(reinterpret_cast<const unsigned char*>(str_out.c_str()), strlen(str_out.c_str()));

    return str_out2;
}
Run Code Online (Sandbox Code Playgroud)

编辑

有用!!!这只是我的一个疏忽,我的套接字在加密之前检查数据的大小并发送该大小而不是加密的字符串大小。解决这个问题,一切都完美无缺。感谢布兰登的帮助!

Bra*_*don 0

我建议的是,在将明文转换为字节进行加密时以及从字节转换为显示字符串以进行“传输”时,您都会遇到文本编码冲突。

尝试这个:

C# 代码

public string Encrypt(string clearText, Encoding encoding)
{
  // use supplied encoding to convert clear text to bytes
  byte[] clearBytes = encoding.GetBytes(clearText);

  byte[] bt = // insert your encrypt code here...
  // bt bytes are *not* ascii or utf8 or anything else.  If you just
  // use an encoding to convert to text, you won't have good results
  // lets use base64 encoding to get a nice display string representation
  // of the bytes
  return Convert.ToBase64String(bt);
}

public string Decrypt(string base64EncryptedString, Encoding encoding)
{
  // decode the base64
  byte[] bt = Convert.FromBase64String(base64EncryptedString);

  byte[] decrypted = // insert your decrypt code here

  // now we have the original bytes.  Convert back to string using the same
  // encoding we used when encrypting
  return encoding.GetString(decrypted);
}


// Usage:
var clearText = "Hello World";
var asciiEncrypted = Encrypt(clearText, Encoding.ASCII);
var decrypted = Decrypt(clearText, Encoding.ASCII); // MUST USE SAME ENCODING

var utf8Encrypted = Encrypt(clearText, Encoding.UTF8);
var utf8Decrypted = Decrypt(clearText, Encoding.UTF8);
Run Code Online (Sandbox Code Playgroud)

您需要在 C++ 代码中进行相同的base64 更改。我不太熟悉 C++ 字符串的编码。我认为如果您在代码中使用硬编码的 C++ 字符串文字,那么它们将是 UTF8。这意味着,一旦您进行 C# 更改、在 C++ 代码中进行 Base64 更改并将 UTF8 传递给 C# 加密/解密方法,您的 C++ 和 C# 代码应该一致。