Como chamar usar .NET RijndaelManaged de COM nativo?

Alguém pode dar exemplo de uso para usarSystem.Security.Cryptography.RijndaelManaged do nativo Win32 usando COM?

Aqui está um exemplo funcional de como usar o .NETSystem.Security.Cryptography.SHA256Managed

Nota: Este é um exemplo de como chamar SHA256Managed enão RijndaelManaged **. Eu mostro este código para introduzir alguns dos conceitos complicados de chamar objetos COM com vinculação antecipada e tardia e para mostrar que chamando objetos .NET com Wrappers de COMé possível. Algumas pessoas podem vomitar as mãos ao ouvir que eu quero misturar o .NET eo Win32 COM.

Nota: A linguagem é Delphi (que é o que eu escrevi e testei), mas transcodificada para parecer um pouco mais como C # ou Java, então a questão é mais acessível a um público mais amplo:

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;

Com a função auxiliar:

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;

A verdadeira razão pela qual eu mostro o código chamandoSHA256Managed é demonstrar as dificuldades que estou encontrando ao passararrays para COM em Delphi. Por exemplo, se você simplesmente confiasseIDispatch ligação tardia:

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

Então, em tempo de execução, você obtémO parâmetro está incorreto; algo sobreIDispatch ligação tardia não suporta passar umOleVariant isso é uma matriz de bytes.

É por isso que eu tenho que passar pelosafearray que está dentro doOleVariant. Como todos nós sabemosVariante é apenas umestrutura sindical, onde nos preocupamos com oSAFEARRAY membro:

data: PSafeArray;

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

Exceto tentando passar umPSafeArray usandoIDispatch ligação tardia faz com que o Delphi aumente:

Tipo não permitido na chamada de automação OLE

É por isso que somos forçados a abandonar parcialmenteIDispatch ligação tardia paraICryptoTransform ligação antecipada:

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

com

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

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

Então deveria ser isso, certo? Nós resolvemos como passar matrizes para objetos COM .NET? eu deveria estar pronto para usarRijndael agora; usar ligação inicial comPSafeArray.

É isso que queremos testar com ligação tardia:

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

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

que falha pela mesma razão acima - você não pode passarOleVariant matrizes para objetos COM (o parâmetro está incorreto).

Então nós devemos apenas usar a ligação inicial deSymmetricAlgorithm.Key e passar oKey como umPSafeArray:

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;

Exceto não háISymmetricAlgorithm interface; eu inventei.

Se você importar a biblioteca de tipos demscorelib.tlb, que contémICryptoTransform, não há ligação antecipadaISymmetricAlgorithm. Láé a atrasado 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;

Então, como posso definir oRijndaelManaged Key eIV do nativo Win32 COM? Que sintaxe de ligação tardia posso usar?

Como chamar usar .NET RijndaelManaged de COM nativo?

Outras tentativas

Como não há limiteinterface eu posso usar, eu tenho que focar em como passar uma matriz de bytesIDispatch. O segredo é o que deveria estar noVariant que eu passo para o objeto COM.

Desde a versão com ligação inicial usadasafearraysvou começar com isso. Primeiro de tudo eu voumanualmente conjuntoOleVariant me estruturar.

Para cada uma das seguintes tentativas, o seguinte é verdadeiro:

key: OleVariant;
data: PSafeArray;

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

definindo oenum variante eu mesmo.

Tentativa 1: VT_ARRAY Um ponteiro SAFEARRAY.

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

Tentativa 2: VT_ARRAY Um ponteiro SAFEARRAY.

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

Tentativa 3: VT_SAFEARRAY Um array seguro. Use VT_ARRAY em VARIANT.

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

Tentativa 4: VT_SAFEARRAY Um array seguro. Use VT_ARRAY em VARIANT.

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

Todos eles falham com umThe parameter is incorrect erro.

Eu tenho a sensação de queVT_ARRAY (um safearray) eVT_SAFEARRAY (um safearray) simplesmente não são o que a interface IDispatch do COM Callable wrapper está preparada para aceitar. Talvez precise serVT_CARRAY.

Ou talvez não. Talvez alguém mais esperto do que eu possa descobrir.

Leitura de bônus

Esta é, essencialmente, uma reformulação de uma pergunta que fiz em 2008 sobre os Newsgroups da Borland.

Compilador Delphi tem conhecimento interno de COM SafeArrays?

.Net mshtml: Como passar um SAFEARRAY BSTR?

questionAnswers(0)

yourAnswerToTheQuestion