59439


C#でAES暗号化していた処理をC++でも利用するために変換を試みているのですが、Crypto++ライブラリを使っての実装ができません。  
暗号化はできているようなのですが、結果が異なってしまいます。

ブロックサイズとキーサイズの指定が怪しいと考えているのですが、どこが要因かわかる方ご教授願えますでしょうか。

C# Code

[code]

    const string AesIV = @"1234567890123456";
    const string AesKey = @"ABCDEFGHIJKLMNOP";
    string strText = "暗号化テスト";
    
    AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
    aes.BlockSize = 128;
    aes.KeySize = 128;
    aes.IV = Encoding.UTF8.GetBytes(AesIV);
    aes.Key = Encoding.UTF8.GetBytes(AesKey);
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7;
    byte[] byteText = Encoding.UTF8.GetBytes(strText);
    
    byte[] encryptText = aes.CreateEncryptor().TransformFinalBlock(byteText, 0, byteText.Length);
    
[/code]

C++ Code (Crypto++利用)

[code]

    std::string strKey("1234567890123456");
    std::string strIV("ABCDEFGHIJKLMNOP");
    std::string strText = "暗号化テスト";
    
    std::string stEncryptText;
    
    CryptoPP::AES::Encryption aesEncryption((CryptoPP::byte*)strKey.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH);
    CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, (CryptoPP::byte*)strIV.c_str());
    
    CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(stEncryptText), CryptoPP::BlockPaddingSchemeDef::PKCS_PADDING);
    stfEncryptor.Put(reinterpret_cast<const unsigned char*>(strText.c_str()), strText.length());
    stfEncryptor.MessageEnd();
    
[/code]


CC BY-SA 4.0
2019-09-27T03:23:17.590
59314
2023-05-07T03:34:44.173
2023-05-07T03:34:44.173
4236
35986
question
c# c++ encoding encryption
AES暗号化処理をC#からC++に変換したい


コメントでの指摘の通り、平文データに相違があることが考えられます。

さらに、鍵とIVに文字列を使っているのが2つの点でまずいです。

# セキュリティ的に問題

安全に暗号を運用するには、鍵やIVは乱数かパスワードをPBKDF2のような鍵導出関数に通して取り出した値を使わなければなりません。その点で、文字列を使っているサンプルコードは参考にしないほうがよいです。

# バイト表現に変換するときに意図しない変換が混入する

例えば`c_str()`で変換すると、末尾に`\0`が含まれるとか、逆に元のデータに`\0`が含まれているとそこで文字列が千切れるということが起きます。

> CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption,
> (CryptoPP::byte*)strIV.c_str());

このコードで渡しているのは、`"ABCDEFGHIJKLMNOP"`ではなく`"ABCDEFGHIJKLMNOP**\0**"`(へのポインタ)ですが、きちんと理解されてますか。内部的にはIVの長さ分しか参照しないでしょうからこれ自体が直接問題を引き起こすことはない気がしますが、バグの種ではあります。

動作を理解する段階であれば、平文も含めて文字列ではなくバイト配列を用いて検証するのがよいでしょう。それであれば平文のエンコードの違いで引っかかることもありません。


CC BY-SA 4.0
2019-10-03T21:48:59.543
59438
2019-10-03T21:48:59.543
5793
59314
answer


>
[code]

>     // C#
>     byte[] byteText = Encoding.UTF8.GetBytes(strText);
>  
>     // C++
>     std::string strText = "暗号化テスト";
>  
[/code]

C#は見ての通りUTF-8エンコーディングのバイト列となります。Visual
StudioのC++とのことですが、こちらはコントロールパネルの「Unicode
対応ではないプログラムの言語」の設定値で日本語環境ではShift_JISエンコーディングとなります。このため、入力バイト列がそもそも異なります。

UTF-8で一致させるには[UTF-8文字列リテラル](https://cpprefjp.github.io/lang/cpp11/utf8_string_literals.html)が簡単ですがお使いのVisual
Studio 2013では未対応です。Visual Studio
2015以降を使用されるか、[wctomb](https://docs.microsoft.com/ja-jp/cpp/c-runtime-
library/reference/wctomb-wctomb-l?view=vs-2019)等で変換することになります。

[code]

    // C#
    byte[] byteText = Encoding.UTF8.GetBytes(strText);
    // C++
    std::string strText = u8"暗号化テスト";
    
[/code]

「Unicode
対応ではないプログラムの言語」で一致させるには[Encoding.Default](https://docs.microsoft.com/ja-
jp/dotnet/api/system.text.encoding.default?view=netframework-4.8)を使用します。

[code]

    // C#
    byte[] byteText = Encoding.Default.GetBytes(strText);
    // C++
    std::string strText = "暗号化テスト";
    
[/code]

* * *

> ソースコードのエンコーディングをUTF-8（プロパティのC++コマンドラインで指定）にしてみましたが変わらずでした。

補足しますと、Visual
C++ではソースコードを解釈し一旦Unicodeに変換しています。その上で、指定されたエンコーディングのバイト列に変換してコード生成しています。そのため、ソースコードがUTF-8エンコーディングであっても
`""` 文字列は **コンパイル環境** の「Unicode
対応ではないプログラムの言語」に沿ったバイト列（すなわち日本語環境においてはShift_JIS）となります。

一方、C#の`Encoding.Default`は **実行環境** の「Unicode
対応ではないプログラムの言語」に沿ったバイト列となります。同じ設定でも参照するタイミングが異なる点には気を付ける必要があります。


CC BY-SA 4.0
2019-10-03T23:06:01.343
59439
2019-10-07T06:51:18.423
2019-10-07T06:51:18.423
4236
4236
59314
answer