C ++ / CLI AES 256位加密

编程入门 行业动态 更新时间:2024-10-23 09:32:12
本文介绍了C ++ / CLI AES 256位加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

到目前为止,我发现的大多数示例和问题仅适用于C#,但是我试图将以下C#代码重现为C ++ / CLI:

Most examples and questions I've found so far is for C# only, however I'm trying to reproduce the following C# code into C++/CLI:

using System.Security.Cryptography; using System.IO; public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes) { byte[] encryptedBytes = null; // Set your salt here, change it to meet your flavor: // The salt bytes must be at least 8 bytes. byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; using (MemoryStream ms = new MemoryStream()) { using (RijndaelManaged AES = new RijndaelManaged()) { AES.KeySize = 256; AES.BlockSize = 128; var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); AES.Key = key.GetBytes(AES.KeySize / 8); AES.IV = key.GetBytes(AES.BlockSize / 8); AES.Mode = CipherMode.CBC; using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write)) { cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length); cs.Close(); } encryptedBytes = ms.ToArray(); } } return encryptedBytes; } public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes) { byte[] decryptedBytes = null; // Set your salt here, change it to meet your flavor: // The salt bytes must be at least 8 bytes. byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; using (MemoryStream ms = new MemoryStream()) { using (RijndaelManaged AES = new RijndaelManaged()) { AES.KeySize = 256; AES.BlockSize = 128; var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); AES.Key = key.GetBytes(AES.KeySize / 8); AES.IV = key.GetBytes(AES.BlockSize / 8); AES.Mode = CipherMode.CBC; using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length); cs.Close(); } decryptedBytes = ms.ToArray(); } } return decryptedBytes; } //Encrypt String public string EncryptText(string input, string password) { // Get the bytes of the string byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input); byte[] passwordBytes = Encoding.UTF8.GetBytes(password); // Hash the password with SHA256 passwordBytes = SHA256.Create().ComputeHash(passwordBytes); byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes); string result = Convert.ToBase64String(bytesEncrypted); return result; } //Decrypt String public string DecryptText(string input, string password) { // Get the bytes of the string byte[] bytesToBeDecrypted = Convert.FromBase64String(input); byte[] passwordBytes = Encoding.UTF8.GetBytes(password); passwordBytes = SHA256.Create().ComputeHash(passwordBytes); byte[] bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes); string result = Encoding.UTF8.GetString(bytesDecrypted); return result; }

这是我到目前为止所得到的:

This is what I got so far:

using namespace System::Security::Cryptography; using namespace System::IO; private: array<unsigned char>^ AES_Encrypt(array<unsigned char>^ bytesToBeEncrypted, array<unsigned char>^ passwordBytes) { array<unsigned char>^ encryptedBytes = nullptr; // Set your salt here, change it to meet your flavor: // The salt bytes must be at least 8 bytes. array<unsigned char>^ saltBytes = gcnew array<unsigned char>(8) { 1, 2, 3, 4, 5, 6, 7, 8 }; MemoryStream^ ms = gcnew MemoryStream(); RijndaelManaged^ AES = gcnew RijndaelManaged(); auto cs = gcnew CryptoStream(ms, AES->CreateEncryptor(), CryptoStreamMode::Write); try { try { AES->KeySize = 256; AES->BlockSize = 128; AES->Padding = System::Security::Cryptography::PaddingMode::Zeros; auto key = gcnew Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); AES->Key = key->GetBytes(AES->KeySize / 8); AES->IV = key->GetBytes(AES->BlockSize / 8); AES->Mode = CipherMode::CBC; try { cs->Write(bytesToBeEncrypted, 0, bytesToBeEncrypted->Length); cs->Close(); } finally { if (cs != nullptr) delete cs; } encryptedBytes = ms->ToArray(); } finally { if (AES != nullptr) delete AES; } } finally { if (ms != nullptr) delete ms; } return encryptedBytes; } private: array<unsigned char>^ AES_Decrypt(array<unsigned char>^ bytesToBeDecrypted, array<unsigned char>^ passwordBytes) { array<unsigned char>^ decryptedBytes = nullptr; // Set your salt here, change it to meet your flavor: // The salt bytes must be at least 8 bytes. array<unsigned char>^ saltBytes = gcnew array<unsigned char>(8) { 1, 2, 3, 4, 5, 6, 7, 8 }; MemoryStream^ ms = gcnew MemoryStream(); RijndaelManaged^ AES = gcnew RijndaelManaged(); auto cs = gcnew CryptoStream(ms, AES->CreateDecryptor(), CryptoStreamMode::Write); try { try { AES->KeySize = 256; AES->BlockSize = 128; AES->Padding = System::Security::Cryptography::PaddingMode::Zeros; auto key = gcnew Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); AES->Key = key->GetBytes(AES->KeySize / 8); AES->IV = key->GetBytes(AES->BlockSize / 8); AES->Mode = CipherMode::CBC; try { cs->Write(bytesToBeDecrypted, 0, bytesToBeDecrypted->Length); cs->Close(); } finally { if (cs != nullptr) delete cs; } decryptedBytes = ms->ToArray(); } finally { if (AES != nullptr) delete AES; } } finally { if (ms != nullptr) delete ms; } return decryptedBytes; } //Encrypt String private: System::String^ EncryptText(System::String^ input, System::String^ password) { // Get the bytes of the string array<unsigned char>^ bytesToBeEncrypted = System::Text::Encoding::UTF8->GetBytes(input); array<unsigned char>^ passwordBytes = System::Text::Encoding::UTF8->GetBytes(password); // Hash the password with SHA256 passwordBytes = SHA256::Create()->ComputeHash(passwordBytes); array<unsigned char>^ bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes); System::String^ result = Convert::ToBase64String(bytesEncrypted); return result; } //Decrypt String private: System::String^ DecryptText(System::String^ input, System::String^ password) { // Get the bytes of the string array<unsigned char>^ bytesToBeDecrypted = Convert::FromBase64String(input); array<unsigned char>^ passwordBytes = System::Text::Encoding::Encoding::UTF8->GetBytes(password); passwordBytes = SHA256::Create()->ComputeHash(passwordBytes); array<unsigned char>^ bytesDecrypted = AES_Decrypt(bytesToBeDecrypted, passwordBytes); System::String^ result = System::Text::Encoding::Encoding::UTF8->GetString(bytesDecrypted); return result; }

加密工作正常,我做了一个简单的测试,将其更新为标签:

The Encryption is working fine, I did a simple test to update it into a label:

private: System::Void Button1_Click(System::Object^ sender, System::EventArgs^ e) { System::String^ temp = EncryptText(this->textBox1->Text, "batman"); this->label1->Text = temp; this->label2->Text = DecryptText(temp, "batman"); }

但是解密时遇到一些问题,我设法 CryptographicException :

However I'm getting some issues when Decrypting it, I managed to catch the CryptographicException:

'EncryptionTest.exe' (Win32): Loaded 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\diasymreader.dll'. System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed. at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) at System.Security.Cryptography.CryptoStream.FlushFinalBlock() at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing) at System.IO.Stream.Close() at EncryptionTest.MyForm.AES_Decrypt(Byte[] bytesToBeDecrypted, Byte[] passwordBytes) in C:\Users\[username]\source\repos\EncryptionTest\EncryptionTest\MyForm.h:line 198

第198行是到最后一个尝试块: cs-> Close();

Line 198 refers to the last try block: cs->Close();

我尝试了所有可用的填充,例如 ANSIX923 , ISO10126 , PKCS7 ,但没有帮助了。

I tried all kind of available paddings though, such as ANSIX923, ISO10126, PKCS7, but none helped. I'd appreciate any help you're able to provide.

推荐答案

在C ++ / CLI中设置AES参数太晚了,我将不胜感激。代码,即之后创建加密器和解密器。因此,自动生成的随机密钥和 RijndaelManaged 实例的IV和其他默认值(PKCS7,CBC等)用于创建加密器和解密器(而不是密钥)。和IV使用 Rfc2898DeriveBytes 实例以及其余指定值生成)。由于随机性,密钥和IV对于加密和解密是不同的,因此解密失败。因此,必须在创建加密器和解密器之前设置AES参数,即正确的顺序是(使用加密示例):

The AES parameters are set too late in the C++/CLI code, that is, after the creation of encryptor and decryptor. Therefore, an automatically generated random key and IV and other default values (PKCS7, CBC, etc.) of the RijndaelManaged instance are used to create encryptor and decryptor (instead of the key and IV generated with the Rfc2898DeriveBytes instance and the rest of the specified values). Because of the randomness, key and IV are different for encryption and decryption and thus decryption fails. Therefore, the AES parameters must be set before encryptor and decryptor are created, i.e. the correct order is (using the example of encryption):

AES->KeySize = 256; AES->BlockSize = 128; AES->Mode = CipherMode::CBC; AES->Padding = System::Security::Cryptography::PaddingMode::Zeros; auto key = gcnew Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); AES->Key = key->GetBytes(AES->KeySize / 8); AES->IV = key->GetBytes(AES->BlockSize / 8); auto cs = gcnew CryptoStream(ms, AES->CreateEncryptor(), CryptoStreamMode::Write);

顺便说一句,密钥大小,块大小和模式的值对应于默认值。填充的默认值为PKCS7,与注释中提到的零填充相比,填充是更可靠的填充。

By the way, the values for key size, block size and mode correspond to the default values. The default value for padding is PKCS7, which is the more reliable padding compared to zero padding, as already noted in the comments.

更多推荐

C ++ / CLI AES 256位加密

本文发布于:2023-11-09 09:45:53,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1572051.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:CLI   AES

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!