Frage Warum unterscheiden sich meine Bytes in der vierten Runde dieses C # -Ports eines Verschlüsselungsalgorithmus?


Ich versuche, den C ++ - Code nach C # zu portieren und funktioniert größtenteils, allerdings nur für die ersten drei Runden der Schleife. In der vierten Runde beginnen sich die Bytes für den Eingangsblock zu unterscheiden und ich verstehe nicht warum. Wenn wir annehmen, dass die C ++ - Version die korrekte Implementierung ist, warum gibt der C # -Code in der vierten Runde ein anderes Ergebnis. Im Folgenden sind meine Ergebnisse und der Code (beide Konsolenanwendungen für C ++ / CLR und C #)

Ich denke, etwas ist anders mit der Art, wie der Eingabeblock in jeder Runde erstellt wird, bevor er an AES übergeben wird (in C ++ gibt es eine Methode zum Konvertieren in und aus der Basis 256, to_base_256 und von_base_256) aber in C # konvertiere ich das Basis-256-Byte-Array direkt zu BigInteger und dann zurück zum Byte-Array. Ich weiß nur nicht, wieso beide identische Eingangsblockwerte für die ersten drei Runden ergeben würden, aber nicht für die vierte.

BEARBEITEN: Nach mehr Debugging beschränkte ich mich darauf, wo das Problem beginnt, bis zu dieser Zeile in der for-Schleife, wenn i = 2 (Runde 3)

BigInteger AESResult = new BigInteger(t);

Nach der AES-Verschlüsselung des Bausteins enthält mein Byte-Array t

23, 111, 30, 144, 117, 161, 87, 113, 157, 52, 215, 157, 130, 135, 20, 184

Aber wenn ich diese Bytes mit der obigen Zeile in BigInteger umwandle, wird das Zeichen auf dem Wert plötzlich zu negativ und von dort geht es bergab. Der Wert wird nicht wie in den vorherigen Runden in den lokalen Fenstern angezeigt.

ERGEBNISSE

RUNDE 1

EINGANG
  C ++ 224,144,103,1,0,0,0,0,0,0,0,0,0,0,0,0,
  C # 224,144,103,1,0,0,0,0,0,0,0,0,0,0,0,0,
  AES VERSCHLÜSSELT
  C ++ 175,19,208,16,98,242,219,41,136,137,124,214,117,242,222,20,
  C # 175,19,208,16,98,242,219,41,136,137,124,214,117,242,222,20,

RUNDE 2

EINGANG
  C ++ 168,68,153,2,0,0,0,0,0,0,0,0,1,0,0,0,
  C # 168,68,153,2,0,0,0,0,0,0,0,0,1,0,0,0,
  AES VERSCHLÜSSELT
  C ++ 182,186,181,102,204,102,32,32,232,213,226,133,59,128,225,109,
  C # 182,186,181,102,204,102,32,32,232,213,226,133,59,128,225,109,

3. RUNDE

EINGANG
  C ++ 150,126,97,5,0,0,0,0,0,0,0,0,2,0,0,0,
  C # 150,126,97,5,0,0,0,0,0,0,0,0,2,0,0,0,
  AES VERSCHLÜSSELT
  C ++ 23,111,30,144,117,161,87,113,157,52,215,157,130,135,20,184,
  C # 23,111,30,144,117,161,87,113,157,52,215,157,130,135,20,184,

4. RUNDE

EINGANG
C ++ 191, 210,191,0,0,0,0,0,0,0,0,0,3,0,0,0,
C # 191,255,174,252,0,0,0,0,0,0,0,0,3,0,0,0,
  AES VERSCHLÜSSELT
  C ++ 130,187,182,115,251,12,63,157,109,110,234,35,137,208,172,203,
  C # 248,197,125,177,46,103,91,217,246,8,202,219,115,4,213,37,

C ++ CLR Konsolenanwendung

// ConsoleApplication2.cpp : main project file.

#include "stdafx.h"

using namespace System;
using namespace System::Security::Cryptography;


void unpack(unsigned int a, unsigned char *b)
{ /* unpack bytes from a word */
    b[0] = unsigned char(a);
    b[1] = unsigned char(a >> 8);
    b[2] = unsigned char(a >> 16);
    b[3] = unsigned char(a >> 24);

}

array<unsigned char>^ AES_encrypt_block(array<unsigned char>^ plainText)
{
    array<unsigned char>^ key = gcnew array<unsigned char>(16);
    key[0] = 0x01; key[1] = 0x01; key[2] = 0x01; key[3] = 0x01; key[4] = 0x01; key[5] = 0x01; key[6] = 0x01; key[7] = 0x01;
    key[8] = 0x01; key[9] = 0x01; key[10] = 0x01; key[11] = 0x01; key[12] = 0x01; key[13] = 0x01; key[14] = 0x01; key[15] = 0x01;

    AesManaged^ AES = gcnew AesManaged();
    AES->BlockSize = 128;
    AES->KeySize = 128;
    AES->Key = key;
    AES->Mode = CipherMode::ECB;
    AES->Padding = PaddingMode::None;

    array<unsigned char>^ output_buffer = gcnew array<unsigned char>(16);

    ICryptoTransform^ encryptor = AES->CreateEncryptor(AES->Key, AES->IV);
    encryptor->TransformBlock(plainText, 0, plainText->Length, output_buffer, 0);

    return output_buffer;
}

void from_base_256(unsigned char *y, int len, int s, char *x)
{
    int i, m, n;
    unsigned int c, d;

    m = 16;
    n = 0; c = 0;
    for (;;)
    {
        while (m>0 && y[m - 1] == 0) m--;
        d = 0;

        for (i = m - 1; i >= 0; i--)
        {
            d = (d << 8) + y[i];
            y[i] = d / s;
            d %= s;
        }


        d += c + x[n]; c = 0;
        if ((int)d >= s)
        {
            c = 1; x[n] = d - s;
        }
        else x[n] = d;

        n++;
        if (n >= len) break;
    }
}

int to_base_256(char *x, int len, int s, unsigned char *y)
{
    int i, j, m;
    unsigned int c;

    for (i = 0; i<16; i++)
        y[i] = 0;
    if (len == 0) return 0;

    m = 1; y[0] = x[len - 1];
    for (j = len - 2; j >= 0; j--)
    { 
        c = x[j];
        for (i = 0; i<m; i++)
        {
            c += (unsigned int)y[i] * s;
            y[i] = c & 0xff;
            c >>= 8;
        }
        if (c>0) { m++; y[m - 1] = c; }
    }

    return m;
}



int main(array<System::String ^> ^args)
{


    int i, n;

    //PLAINTEXT
    char x[256]; 
    x[0] = 1; x[1] = 4; x[2] = 2; x[3] = 5; x[4] = 6; x[5] = 9; x[6] = 8; x[7] = 7;
    x[8] = 2; x[9] = 1; x[10] = 5; x[11] = 4; x[12] = 6; x[13] = 5; x[14] = 3; x[15] = 2;

    unsigned int TL, TR;

    TR = 0;     
    TL = 0;

    int j;
    char *left, *right;
    unsigned char buff[16];
    int l, r;
    l = r = 16 / 2;
    if (16 % 2 == 1) l++;

    left = &x[0]; right = &x[l];

    for (j = 0; j < 8; j++)
    {
        System::Diagnostics::Debug::WriteLine("");
        System::Diagnostics::Debug::WriteLine("ROUND " + (j+1));

        if (j % 2 == 0)
        {
            to_base_256(right, r, 10, buff);

            unpack(TR^j, &buff[12]);

            int size = sizeof(buff) / sizeof(*buff);
            array<unsigned char>^ inputPlaintext = gcnew array<unsigned char>(size);
            for (int i = 0; i < size; i++)
                inputPlaintext[i] = buff[i];

            System::Diagnostics::Debug::WriteLine("");
            System::Diagnostics::Debug::WriteLine("INPUT");
            for (int z = 0; z < size; z++)
                System::Diagnostics::Debug::Write(inputPlaintext[z] + ",");

            array<unsigned char>^ result = AES_encrypt_block(inputPlaintext);

            System::Diagnostics::Debug::WriteLine("");
            System::Diagnostics::Debug::WriteLine("AES ENCRYPTED");
            for (int z = 0; z < size; z++)
                System::Diagnostics::Debug::Write(result[z] + ",");

            pin_ptr<unsigned char>buff = &result[0];

            from_base_256( buff, l, 10, left);

            System::Diagnostics::Debug::WriteLine("");
            System::Diagnostics::Debug::WriteLine("afterFromBase256 - left");
            for (int z = 0; z < sizeof(left) / sizeof(*left); z++)
                System::Diagnostics::Debug::Write(left[z] + " , ");
        }
        else
        {
            to_base_256(left, l, 10, buff);

            unpack(TL^j, &buff[12]);

            int size = sizeof(buff) / sizeof(*buff);
            array<unsigned char>^ inputPlaintext = gcnew array<unsigned char>(size);
            for (int i = 0; i < size; i++)
                inputPlaintext[i] = buff[i];

            System::Diagnostics::Debug::WriteLine("");
            System::Diagnostics::Debug::WriteLine("INPUT");
            for (int z = 0; z < size; z++)
                System::Diagnostics::Debug::Write(inputPlaintext[z] + ",");

            array<unsigned char>^ result = AES_encrypt_block(inputPlaintext);

            System::Diagnostics::Debug::WriteLine("");
            System::Diagnostics::Debug::WriteLine("AES ENCRYPTED");
            for (int z = 0; z < size; z++)
                System::Diagnostics::Debug::Write(result[z] + ",");

            pin_ptr<unsigned char>buff = &result[0];

            from_base_256( buff, r, 10, right);

            System::Diagnostics::Debug::WriteLine("");
            System::Diagnostics::Debug::WriteLine("afterFromBase256 - right");
            for (int z = 0; z < sizeof(right) / sizeof(*right); z++)
                System::Diagnostics::Debug::Write(right[z] + " , ");
        }
    }

    return 0;
}

C # -Konsolenanwendung

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

namespace BPS_ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {

            //integer array to hold the bytes of plaintext 
            int[] plaintext = new int[16] { 1, 4, 2, 5, 6, 9, 8, 7, 2, 1, 5, 4, 6, 5, 3, 2 };

            byte[] key = new byte[16];
            key[0] = 0x01; key[1] = 0x01; key[2] = 0x01; key[3] = 0x01; key[4] = 0x01; key[5] = 0x01; key[6] = 0x01; key[7] = 0x01;
            key[8] = 0x01; key[9] = 0x01; key[10] = 0x01; key[11] = 0x01; key[12] = 0x01; key[13] = 0x01; key[14] = 0x01; key[15] = 0x01;

            //Block Cipher - AES-128
            AES AESEncrypt = new AES(key);

            int bits = 128 - 32; //128 block for AES-128

            //tweak
            int tweak = 0; //64 bit user provided tweak value
            int TR = 0; //left side of tweak
            int TL = 0; //right side of tweak

            int s = 10;

            int w = 8; //recommended number of rounds

            int BLOCK_SIZE = 16; //block size in bytes (16 = 128 bits for AES-128)
            int b = 0; //s-integer input length


            b = plaintext.Length;

            //Split the tweak into right and left
            //

            TR = tweak % (1 << 32);
            TL = (tweak - TR) / (1 << 32);

            //Split the plaintext into left and right substrings
            //
            int j = 0;
            int[] XR; //right substring
            int[] XL; //left substring

            int l; //length of left substring
            int r; //length of right substring

            if (b % 2 == 1) //b is odd
            {
                l = (b + 1) / 2;
                r = (b - 1) / 2;
            }
            else //b is even
            {
                l = r = b / 2;
            }

            XL = new int[l];
            XR = new int[r];

            for (int i = 0; i < l; i++)
                XL[i] = plaintext[i];

            j = 0;
            for (int i = l; i <= l + r - 1; i++, j++)
                XR[j] = plaintext[i];


            //initialize left and right branches

            BigInteger L = 0;

            for (int i = 0; i < l; i++)
            {
                L += XL[i] * BigInteger.Pow(s, i);
            }

            BigInteger R = 0;

            for (int i = 0; i < l; i++)
            {
                R += XR[i] * BigInteger.Pow(s, i);
            }


            byte[] initial_Lbytes = L.ToByteArray();
            byte[] initial_Rbytes = R.ToByteArray();

            int[] intitial_L = new int[l];
            int[] intitial_R = new int[r];

            foreach (byte bL in initial_Lbytes)
            {
                BigInteger num = new BigInteger(new byte[] { bL });
            }

            //8 Rounds
            for (int i = 0; i < 8; i++)
            {
                System.Diagnostics.Debug.WriteLine("");
                System.Diagnostics.Debug.WriteLine("ROUND " + (i + 1));

                if (i % 2 == 0) //even
                {
                    byte[] RBytes = R.ToByteArray();

                    byte[] inputPlaintext = new byte[16];
                    for (int k = 0; k < RBytes.Length; k++)
                        inputPlaintext[k] = RBytes[k];

                    inputPlaintext = INT2LE(TR ^ i, inputPlaintext);

                    System.Diagnostics.Debug.WriteLine("INPUT");
                    foreach (byte bb in inputPlaintext)
                        System.Diagnostics.Debug.Write(bb + ",");

                    byte[] t = AESEncrypt.Encrypt(inputPlaintext);

                    System.Diagnostics.Debug.WriteLine("");
                    System.Diagnostics.Debug.WriteLine("AES ENCRYPTED");
                    foreach (byte bb in t)
                        System.Diagnostics.Debug.Write(bb + ",");

                    BigInteger AESResult = new BigInteger(t);

                    BigInteger res = (L + AESResult) % BigInteger.Pow(s, l);

                    L = res;

                }
                else //odd
                {

                    byte[] LBytes = L.ToByteArray();


                    byte[] inputPlaintext = new byte[16];
                    for (int k = 0; k < LBytes.Length; k++)
                        inputPlaintext[k] = LBytes[k];

                    inputPlaintext = INT2LE(TL ^ i, inputPlaintext);

                    System.Diagnostics.Debug.WriteLine("INPUT");
                    foreach (byte bb in inputPlaintext)
                        System.Diagnostics.Debug.Write(bb + ",");

                    byte[] t = AESEncrypt.Encrypt(inputPlaintext);

                    System.Diagnostics.Debug.WriteLine("");
                    System.Diagnostics.Debug.WriteLine("AES ENCRYPTED");
                    foreach (byte bb in t)
                        System.Diagnostics.Debug.Write(bb + ",");

                    BigInteger AESResult = new BigInteger(t);

                    BigInteger res = (R + AESResult) % BigInteger.Pow(s, r);

                    R = res;
                }
            }

            BigInteger FINAL_R = R;
            BigInteger FINAL_L = L;

        }

        public static byte[] INT2LE(Int32 data, byte[] arr)
        {
            byte[] b = arr;
            b[12] = (byte)data;
            b[13] = (byte)(((uint)data >> 8) & 0xFF);
            b[14] = (byte)(((uint)data >> 16) & 0xFF);
            b[15] = (byte)(((uint)data >> 24) & 0xFF);
            return b;
        }
    }


    public class AES : IBlockCipher
    {
        private byte[] _key;
        public AES(byte[] key)
        {
            _key = key;
        }
        public byte[] Encrypt(byte[] input)
        {
            byte[] output_buffer = new byte[16];
            using (AesManaged E = new AesManaged())
            {
                E.BlockSize = 128;
                E.KeySize = 128;
                E.Mode = CipherMode.ECB;
                E.Key = _key;
                E.Padding = PaddingMode.None;
                //E.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = E.CreateEncryptor(E.Key, E.IV);
                encryptor.TransformBlock(input, 0, 16, output_buffer, 0);

            }

            //return encrypted;
            return output_buffer;
        }
    }

    interface IBlockCipher
    {
        byte[] Encrypt(byte[] input);
    }


}

12
2017-10-17 16:04


Ursprung


Antworten:


Die Dokumentation dafür BigInteger-Konstruktor sagt klar aus:

Der Konstruktor erwartet positive Werte im zu verwendenden Byte-Array   Zeichen-und-Betrags-Darstellung, und negative Werte, um zwei zu verwenden   Komplement-Darstellung. Mit anderen Worten, wenn das Bit höchster Ordnung von   Das höchstwertige Byte in Wert wird gesetzt, der resultierende BigInteger-Wert   ist negativ. Abhängig von der Quelle des Byte-Arrays kann dies verursachen   ein positiver Wert wird als negativer Wert fehlinterpretiert.

Es gibt mehrere Möglichkeiten, dies zu beheben, wobei das einfachste darin besteht, einfach ein Null-Byte an das Byte-Array anzuhängen, wenn es andernfalls als negative Zahl interpretiert würde. Hier ist eine einfache Methode, dies zu tun.

public static BigInteger BuildPositiveBigInteger(byte [] littleEndianBytes) {
    if (littleEndianBytes[littleEndianBytes.Length-1] >= 0x80) {
        byte[] newBytes = new byte[littleEndianBytes.Length + 1];
        littleEndianBytes.CopyTo (newBytes, 0);
        return new BigInteger (newBytes);
    } else {
        return new BigInteger (littleEndianBytes);
    }
}

In Ihrem Code ersetzen Sie alle Instanzen von new BigInteger(byte[]) mit Anrufen nach BuildPositiveBigInteger es sollte wie erwartet laufen.


10
2017-10-19 23:25