Can anyone give example usage for using System.Security.Cryptography.RijndaelManaged from native Win32 using COM?
Here is a functional example of how to use .NET's System.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: The language is Delphi (which is what i wrote and tested it in), but transcoded to make it look slightly more like C# or Java, so the question is more accessible to a wider audience:
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;
With the helper function:
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;
The real reason i show code calling SHA256Managed is to demonstrate the difficulties i'm encountering when passing arrays to COM in Delphi. For example, if you simply relied on IDispatch late binding:
sha: OleVariant;
inputBuffer: OleVariant;
...
sha.TransformFinalBlock(inputBuffer, i, count);
Then at runtime you get The parameter is incorrect; something about IDispatch late binding doesn't support passing an OleVariant that is an array of bytes.
That's why i have to instead pass the safearray that is inside the OleVariant. As we all know a Variant is just a union structure, where we care about the SAFEARRAY member:
data: PSafeArray;
data := PSafeArray(TVarData(inputBuffer).VArray);
sha.TransformFinalBlock(data, i, count);
Except trying to pass a PSafeArray using IDispatch late-binding causes Delphi to throw-up:
Type not allowed in OLE Automation call
Which is why we're forced to partially abandon IDispatch late binding for ICryptoTransform early binding:
ICryptoTransform_Native = interface(IDispatch)
['{8ABAD867-F515-3CF6-BB62-5F0C88B3BB11}']
...
function TransformFinalBlock(inputBuffer: PSafeArray; inputOffset: Integer; inputCount: Integer): PSafeArray; safecall;
...
end;
with
crypto: ICryptoTransform;
sha: OleVariant;
inputBuffer: OleVariant;
crypto = IDispatch(sha) as ICryptoTransform;
crypto.TransformFinalBlock(
PSafeArray(TVarData(inputBuffer).VArray), //inputArray,
i, n);
So that should be it, right? We've solved how to pass arrays to COM .NET objects? i should be all set to use Rijndael now; use early-binding with PSafeArray.
This is what we want to try with late-binding:
OleVariant aes := CreateOleObject('System.Security.Cryptography.RijndaelManaged');
OleVariant keyBytes = VarByteArrayOf(Key);
aes.Key := key;
that fails for the same reason above - you cannot passed OleVariant arrays to COM objects (The parameter is incorrect).
So we we should just use the early binding of SymmetricAlgorithm.Key and pass the Key as a 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;
Except there is no ISymmetricAlgorithm interface; i made it up.
If you import the type library from mscorelib.tlb, which contains ICryptoTransform, there is no early binding ISymmetricAlgorithm. There is a 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;
So how can i set the RijndaelManaged Key and IV from native Win32 COM? What late-binding syntax can i use?
How to call use .NET RijndaelManaged from native COM?
Further Attempts
Since there is no early-bound interface i can use, i have to focus on how to pass a byte array through IDispatch. The secret is what should be in the Variant that i pass to the COM object.
Since the early-bound version used safearrays, i'll start with that. First of all i will manually set OleVariant structure myself.
For each of the following attempts the following is true:
key: OleVariant;
data: PSafeArray;
data := PSafeArray(TVarData(keyBytes).VArray);
setting the variant enum myself.
Attempt 1:
VT_ARRAYA SAFEARRAY pointer.TVarData(key).VType := VT_ARRAY; TVarData(key).VArray := data;Attempt 2:
VT_ARRAYA SAFEARRAY pointer.TVarData(key).VType := VT_ARRAY or VT_I1; TVarData(key).VArray := data;Attempt 3:
VT_SAFEARRAYA safe array. Use VT_ARRAY in VARIANT.TVarData(key).VType := VT_SAFEARRAY or VT_I1; TVarData(key).VArray := data;Attempt 4:
VT_SAFEARRAYA safe array. Use VT_ARRAY in VARIANT.TVarData(key).VType := VT_SAFEARRAY; TVarData(key).VArray := data;
All of them fail with a The parameter is incorrect error.
Get i get the sense that VT_ARRAY (a safearray) and VT_SAFEARRAY (a safearray) are just not what the COM Callable wrapper IDispatch interface is prepared to accept. Perhaps it needs to be VT_CARRAY.
Or maybe not. Maybe someone smarter than me can figure it out.
Bonus Reading
This is, essentially, a re-phrasing of a question i asked in 2008 on the Borland Newsgroups