Как позвонить использовать .NET RijndaelManaged из родного COM?

Может ли кто-нибудь привести пример использования для использованияSystem.Security.Cryptography.RijndaelManaged из родного Win32 с помощью COM?

Вот функциональный пример того, как использовать .NETSystem.Security.Cryptography.SHA256Managed

Note: This is an example of how to call SHA256Managed, and not RijndaelManaged**. i show this code to introduce some of the tricky concepts of calling COM objects with early and late-binding, and to show that calling .NET objects with COM Callable Wrappers is possible. Some people might throw up that hands when hearing i want to mix .NET and Win32 COM.

Note: Язык Delphi (это то, что я написал и протестировал на нем), но перекодированный, чтобы он выглядел немного больше как C # или Java, поэтому вопрос более доступен для более широкой аудитории:

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;

С помощью вспомогательной функции:

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;

Реальная причина, по которой я показываю код звонкаSHA256Managed чтобы продемонстрировать трудности, с которыми я сталкиваюсь при прохожденииarrays COM в Delphi. Например, если вы просто положились наIDispatch позднее связывание:

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

Тогда во время выполнения вы получитеThe parameter is incorrect; Кое-что оIDispatch позднее связывание не поддерживает прохождениеOleVariant это массив байтов.

Вот почему я должен вместо этого передатьsafearray это внутриOleVariant, Как мы все знаемVariant это простопрофсоюзная структурагде мы заботимся оSAFEARRAY член:

data: PSafeArray;

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

За исключением попыток передатьPSafeArray с помощьюIDispatch Позднее связывание приводит к сбою Delphi:

Type not allowed in OLE Automation call

Вот почему мы вынуждены частично отказатьсяIDispatch позднее связываниеICryptoTransform раннее связывание:

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

с

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

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

Так и должно быть, верно? Мы решили, как передавать массивы в объекты COM .NET? я должен быть готов к использованиюRijndael сейчас; использовать раннее связывание сPSafeArray.

Вот что мы хотим попробовать с поздним связыванием:

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

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

что не получается по той же причине, что и выше - вы не можете пройтиOleVariant массивы для COM-объектов (параметр неверен).

Таким образом, мы должны просто использовать раннее связываниеSymmetricAlgorithm.Key и передатьKey какPSafeArray:

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;

Кроме нетISymmetricAlgorithm интерфейс; я сделал это

Если вы импортируете библиотеку типов изmscorelib.tlb, который содержитICryptoTransformнет раннего связыванияISymmetricAlgorithm, Тамis late-bound 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;

Так как я могу установитьRijndaelManaged Key а такжеIV из родного Win32 COM? Какой синтаксис позднего связывания я могу использовать?

Как позвонить использовать .NET RijndaelManaged из родного COM?

Further Attempts

Так как нет раннего связыванияinterface я могу использовать, я должен сосредоточиться на том, как передать байтовый массив черезIDispatch, Секрет в том, что должно быть вVariant что я передаю объекту COM.

Поскольку ранняя версия используетсяsafearraysЯ начну с этого. Прежде всего я будуmanually задаватьOleVariant структурировать себя.

Для каждой из следующих попыток верно следующее:

key: OleVariant;
data: PSafeArray;

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

установкавариант enum себя.

Attempt 1: VT_ARRAY A SAFEARRAY pointer.

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

Attempt 2: VT_ARRAY A SAFEARRAY pointer.

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

Attempt 3: VT_SAFEARRAY A safe array. Use VT_ARRAY in VARIANT.

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

Attempt 4: VT_SAFEARRAY A safe array. Use VT_ARRAY in VARIANT.

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

Все они терпят неудачу сThe parameter is incorrect ошибка.

Получите, я понимаю, чтоVT_ARRAY (защитный щит) иVT_SAFEARRAY (безопасное хранилище) - это не то, что готово принять интерфейс IDispatch оболочки Callable COM. Возможно, это должно бытьVT_CARRAY.

А может и нет. Может, кто-нибудь умнее меня сможет это понять.

Bonus Reading

По сути, это перефразирование вопроса, который я задал в 2008 году в группах новостей Borland.

Delphi compiler has built-in knowledge of COM SafeArrays?

.NET mshtml: How to pass a BSTR SAFEARRAY?

Ответы на вопрос(0)

Ваш ответ на вопрос