1

以下は、C (Windows および C++ (libcrypto++ を使用する Ubuntu)) での cbc および pkcs7 パディング (およびパスワード) 暗号化を使用した aes256 のコードです。暗号化の結果は同じではありません。なぜですか?

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;


public static class AESEncryption
{
    public static string Encrypt(byte[] PlainTextBytes, byte[] KeyBytes, string InitialVector)
        {
            try
            {
                byte[] InitialVectorBytes = Encoding.UTF8.GetBytes(InitialVector);
                RijndaelManaged SymmetricKey = new RijndaelManaged();
                SymmetricKey.Mode = CipherMode.CBC;
               // SymmetricKey.Padding = PaddingMode.PKCS7;
                ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes);
                MemoryStream MemStream = new MemoryStream();
                CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write);
                CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
                CryptoStream.FlushFinalBlock();
                byte[] CipherTextBytes = MemStream.ToArray();
                MemStream.Close();
                CryptoStream.Close();
                //return ByteToHexConversion(CipherTextBytes);

                return Convert.ToBase64String(CipherTextBytes);
            }
            catch (Exception a)
            {
                throw a;
            }
        }
    }
namespace aes
{ class Program
    {

        static void Main(string[] args)
        {

            string FinalValue = AESEncryption.Encrypt( Encoding.ASCII.GetBytes("My Text"),  Encoding.ASCII.GetBytes("My Password"), "0000000000000000");

            Console.WriteLine(FinalValue);

        }
}

}

C++:

#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <cassert>
#include <stdlib.h>
#include <openssl/evp.h>
#include <sstream>
#include "base64.h"

int main()
{


std::string result;
std::stringstream out;

    // ctx holds the state of the encryption algorithm so that it doesn't
    // reset back to its initial state while encrypting more than 1 block.
    EVP_CIPHER_CTX ctx;
    EVP_CIPHER_CTX_init(&ctx);


    std::string keyy="My Password";// in char key[] My Password is written in bytes
    unsigned char key[] = {0x00, 0x00, 0x00, 0x00, 0x00,
                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x4d,0x79, 0x20, 0x50, 0x61, 0x73, 0x73, 0x77,
                   0x6f, 0x72, 0x64};
    unsigned char iv[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
   assert(sizeof(key) == 32);  // AES256 key size
    assert(sizeof(iv) ==  16);   // IV is always the AES block size

    // If data isn't a multiple of 16, the default behavior is to pad with
    // n bytes of value n, where n is the number of padding bytes required
    // to make data a multiple of the block size.  This is PKCS7 padding.
    // The output then will be a multiple of the block size.
    std::string plain("My Text");
    std::vector<unsigned char> encrypted;
    size_t max_output_len  = plain.length() + (plain.length() % 16) + 16;
    encrypted.resize(max_output_len);

    // Enc is 1 to encrypt, 0 to decrypt, or -1 (see documentation).
    EVP_CipherInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv, 1);

    // EVP_CipherUpdate can encrypt all your data at once, or you can do
    // small chunks at a time.
    int actual_size = 0;
    EVP_CipherUpdate(&ctx,
             &encrypted[0], &actual_size,
             reinterpret_cast<unsigned char *>(&plain[0]), plain.size());

    // EVP_CipherFinal_ex is what applies the padding.  If your data is
    // a multiple of the block size, you'll get an extra AES block filled
    // with nothing but padding.
    int final_size;
    EVP_CipherFinal_ex(&ctx, &encrypted[actual_size], &final_size);
    actual_size += final_size;

    encrypted.resize(actual_size);

    for( size_t index = 0; index < encrypted.size(); ++index )
    {
        std::cout << std::hex << std::setw(2) << std::setfill('0') <<
            static_cast<unsigned int>(encrypted[index]);
         //std:: cout<< "val: "<< static_cast<unsigned int>(encrypted[index]) << std::endl;

        out<< std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(encrypted[index]);
    }
    result = out.str();
    std::cout <<"\n"<< result<< "\n";

    EVP_CIPHER_CTX_cleanup(&ctx);


    //
    std::cout<<"decript..\n";


    return 0;
}
4

4 に答える 4

8

c#のIVは「\0」ではなく「0」を含む文字列であり、c++のIVには「\0」が含まれています。「0」と「\0」のASCII値は異なります。

次の行を置き換えます

string FinalValue = AESEncryption.Encrypt( Encoding.ASCII.GetBytes("My Text"),  Encoding.ASCII.GetBytes("My Password"), "0000000000000000");

string FinalValue = AESEncryption.Encrypt( Encoding.ASCII.GetBytes("My Text"),  Encoding.ASCII.GetBytes("My Password"), "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");

それは私が思うトリックを行う必要があります。

20110111

別の結果を叫ぶ必要がありますc#コードで置き換えEncoding.ASCII.GetBytes("My Password")てみてくださいnew byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d,0x79, 0x20, 0x50, 0x61, 0x73, 0x73, 0x77,0x6f, 0x72, 0x64}

于 2011-01-10T14:57:37.947 に答える
3

dvhhの答えを拡張する:

いずれにせよ、ゼロ IV を使用するべきではありません。IV は、同一の平文 (または同一のプレフィックスを持つ平文) が攻撃者と認識できるほど同一であることを回避するのに役立ちます。IV 自体は平文でもかまいません。そのため、IV をランダムに生成し、それを出力の先頭に追加して、復号化を許可することができます。

.NET で安全なランダム IV を取得するには、次のようにします。

byte[] initialVectorBytes = new byte[16];
using(var rng = new RNGCryptoServiceProvider())
    rng.GetBytes(initialVectorBytes);
//...
using(var memStream = new MemoryStream()) {
    memStream.Write(IV,0,16); //to permit decryption later. 
    //...
}

ところで、C# での通常の慣例は、変数またはパラメーター名の先頭に小文字を使用することです。同様にすれば、他の人がコードを読みやすくなります。

于 2011-01-10T15:43:36.860 に答える
1

PHPと.NETWebサービスの間の暗号化に取り組んでいたときに、これと同じ問題に遭遇しました。

PHPとNET間のRijndael暗号化の実用的な例を示すために、githubでサンプルプロジェクトを作成しました 。https ://github.com/dchymko/.NET--PHP-encryption

于 2011-08-08T10:10:23.070 に答える
0

IV を値 0x00 の 16 バイト配列として使用する場合は、C# コードを変更します。

byte[] InitialVectorBytes = Encoding.UTF8.GetBytes(InitialVector);

byte[] InitialVectorBytes = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

3番目のパラメータを省略するように関数を変更することもできます

于 2012-03-31T00:21:21.820 に答える