Как позвонить использовать .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?