Jak dzwonić za pomocą .NET RijndaelZarządzany z rodzimego COM?

Czy ktoś może podać przykład użycia do używaniaSystem.Security.Cryptography.RijndaelManaged z natywnego Win32 przy użyciu COM?

Oto funkcjonalny przykład korzystania z .NETSystem.Security.Cryptography.SHA256Managed

Uwaga: To jest przykład, jak zadzwonić do SHA256Managed inie Rijndael Zarządzane **. pokazuję ten kod, aby przedstawić niektóre z trudnych koncepcji wywoływania obiektów COM z wczesnym i późnym wiązaniem oraz aby pokazać, że wywoływanie obiektów .NET za pomocą COM Callable Wrappersjest możliwy. Niektórzy ludzie mogą rzucić te ręce, słysząc, że chcę połączyć .NET i Win32 COM.

Uwaga: Językiem jest Delphi (to jest to, co napisałem i przetestowałem), ale transkodowane, aby wyglądało nieco bardziej jak C # lub Java, więc pytanie jest bardziej dostępne dla szerszej publiczności:

public static string HashStr256(String szPlaintext)
{
   OleVariant sha = CreateOleObject('System.Security.Cryptography.SHA256Managed');

   OleVariant inputBuffer = VarByteArrayOf(szPlaintext);

   Integer l = VarArrayLowBound(inputBuffer, 1);
   Integer h = VarArrayHighBound(inputBuffer, 1);

   ICryptoTransform crypto = IDispatch(sha) as ICryptoTransform;
   crypto.TransformFinalBlock(
         PSafeArray(TVarData(inputBuffer).VArray), //inputArray,
         l,  //input array offset
         h-l+1); //input array count

   OleVariant digest := sha.Hash;

   Result := ToBase64String(BytesOfVarByteArray(digest));
end;

Z funkcją pomocnika:

function VarByteArrayOf(const s: string): OleVariant;
var
    Data: Pointer;
begin
    //Create variant byte array to hold the bytes
    Result := VarArrayCreate([0, Length(s)-1], varByte);

    //Copy from Delphi array to Variant Array
    if Length(s) > 0 then
    begin
        Data := VarArrayLock(Result);
        try
            System.Move(s[1], Data^, Length(s));
        finally
            VarArrayUnlock(Result);
        end;
    end;
end;

Prawdziwy powód, dla którego pokazuję wywołanie koduSHA256Managed jest pokazanie trudności, które napotykam podczas przechodzeniaarrays do COM w Delphi. Na przykład, jeśli po prostu polegałeśIDispatch późne wiązanie:

sha: OleVariant;
inputBuffer: OleVariant;
...
sha.TransformFinalBlock(inputBuffer, i, count);

Następnie w czasie wykonywania otrzymaszParametr jest niepoprawny; coś oIDispatch późne wiązanie nie wspiera przejściaOleVariant to jest tablica bajtów.

Dlatego muszę przekazaćsafearray to jest w środkuOleVariant. Jak wszyscy wiemyWariant jest po prostustruktura związku, gdzie zależy nam naSAFEARRAY członek:

data: PSafeArray;

data := PSafeArray(TVarData(inputBuffer).VArray);
sha.TransformFinalBlock(data, i, count);

Z wyjątkiem próby przekazaniaPSafeArray za pomocąIDispatch późne wiązanie powoduje, że Delphi rzuca się w górę:

Typ niedozwolony w wywołaniu automatyzacji OLE

Dlatego jesteśmy zmuszeni do częściowego porzuceniaIDispatch późne wiązanie dlaICryptoTransform wczesne wiązanie:

ICryptoTransform_Native = interface(IDispatch)
   ['{8ABAD867-F515-3CF6-BB62-5F0C88B3BB11}']
   ...
   function TransformFinalBlock(inputBuffer: PSafeArray; inputOffset: Integer; inputCount: Integer): PSafeArray; safecall;
   ...
end;

z

crypto: ICryptoTransform;
sha: OleVariant;
inputBuffer: OleVariant;

crypto = IDispatch(sha) as ICryptoTransform;
crypto.TransformFinalBlock(
         PSafeArray(TVarData(inputBuffer).VArray), //inputArray,
         i, n);

Więc to powinno być, prawda? Rozwiązaliśmy sposób przekazywania tablic do obiektów COM .NET? powinienem być gotowy do użyciaRijndael teraz; używaj wczesnego wiązania zPSafeArray.

To właśnie chcemy wypróbować z późnym wiązaniem:

OleVariant aes := CreateOleObject('System.Security.Cryptography.RijndaelManaged');

OleVariant keyBytes = VarByteArrayOf(Key);
aes.Key := key;

to z tego samego powodu nie powiedzie się - nie możesz przejśćOleVariant tablice do obiektów COM (parametr jest niepoprawny).

Powinniśmy więc użyć wczesnego wiązaniaSymmetricAlgorithm.Key i przekazaćKey jakPSafeArray:

var
   symmetric: ISymmetricAlgorithm;
   aes: OleVariant;
   keyBytes: OleVariant;
begin
   aes := CreateOleObject('System.Security.Cryptography.RijndaelManaged');

   symmetric:= (IDispatch(aes) as ISymmetricAlgorithm;
   symmetric.Key := PSafeArray(TVarData(inputBuffer).VArray);
   ...
end;

Z wyjątkiem, że nie maISymmetricAlgorithm berło; wymyśliłem to.

Jeśli importujesz bibliotekę typów zmscorelib.tlb, który zawieraICryptoTransform, nie ma wczesnego wiązaniaISymmetricAlgorithm. Tamjest a spóźniony ISymmetricAlgorithm:

IID__SymmetricAlgorithm: TGUID = '{05BC0E38-7136-3825-9E34-26C1CF2142C9}';
CLASS_SymmetricAlgorithm: TGUID = '{5B67EA6B-D85D-3F48-86D2-8581DB230C43}';
_SymmetricAlgorithm = interface;
SymmetricAlgorithm = _SymmetricAlgorithm;

_SymmetricAlgorithm = interface(IDispatch)
   ['{05BC0E38-7136-3825-9E34-26C1CF2142C9}']
end;
_SymmetricAlgorithmDisp = dispinterface
   ['{05BC0E38-7136-3825-9E34-26C1CF2142C9}']
end;

Więc jak mogę ustawićRijndaelManaged Key iIV z natywnego Win32 COM? Jakiej późnej składni mogę użyć?

Jak dzwonić za pomocą .NET RijndaelZarządzany z rodzimego COM?

Dalsze próby

Ponieważ nie ma wcześniejszego wejściainterface Mogę użyć, muszę się skupić na tym, jak przekazać tablicę bajtówIDispatch. Sekret jest tym, co powinno być wVariant że przechodzę do obiektu COM.

Od czasu użycia wersji wcześniejszejsafearrayszacznę od tego. Przede wszystkim będęręcznie zestawOleVariant skonstruować siebie.

Dla każdej z następujących prób obowiązuje:

key: OleVariant;
data: PSafeArray;

data := PSafeArray(TVarData(keyBytes).VArray);

ustawianiewariant enum sam.

Próba 1: VT_ARRAY Wskaźnik SAFEARRAY.

TVarData(key).VType := VT_ARRAY;
TVarData(key).VArray := data;

Próba 2: VT_ARRAY Wskaźnik SAFEARRAY.

TVarData(key).VType := VT_ARRAY or VT_I1;
TVarData(key).VArray := data;

Próba 3: VT_SAFEARRAY Bezpieczna tablica. Użyj VT_ARRAY w VARIANT.

TVarData(key).VType := VT_SAFEARRAY or VT_I1;
TVarData(key).VArray := data;

Próba 4: VT_SAFEARRAY Bezpieczna tablica. Użyj VT_ARRAY w VARIANT.

TVarData(key).VType := VT_SAFEARRAY;
TVarData(key).VArray := data;

Wszystkie z nich zawodząThe parameter is incorrect błąd.

Rozumiem toVT_ARRAY (safearray) iVT_SAFEARRAY (asekuracja) nie jest tym, co gotowy jest zaakceptować interfejs IDispatch opakowującego COM. Być może tak musi byćVT_CARRAY.

Albo może nie. Może ktoś mądrzejszy ode mnie może to zrozumieć.

Czytanie premii

Jest to zasadniczo powtórzenie pytania, które zadałem w 2008 r. Na temat grup dyskusyjnych Borland

Kompilator Delphi ma wbudowaną znajomość COM SafeArrays?

.NET mshtml: Jak przekazać BSTR SAFEARRAY?

questionAnswers(0)

yourAnswerToTheQuestion