WinBatch® Technical Support Forum

Archived Boards => COM Automation and dotNet => Topic started by: stanl on April 04, 2014, 11:24:34 AM

Title: Can CLR work with secure strings?
Post by: stanl on April 04, 2014, 11:24:34 AM
Thought I'd ask.  Saw some code that uses

System.Security.SecureString  to encrypt information, then two methods from

system.runtime.interopservices.marshal to interpret:

Marshal.SecureStringToCoTaskMemUnicode

and

Marshal.PtrToStringUni


Title: Re: Can CLR work with secure strings?
Post by: stanl on April 07, 2014, 05:31:35 AM
This will probably end up as another one of those classes the CLR cannot handle, but I gave it a shot.  Attached are two files, (1) the text "Hello, I am safe." as a secure string, (2) a WB script that attempts to interpret it.

The script will fail by (1) inability to create the secretdata.txt as a secure string, and inability to recognize SecureStringToGlobalAllocUnicode as a method.

I realize there are existing API's to secure passwords or data, but this looks interesting.
Title: Re: Can CLR work with secure strings?
Post by: stanl on April 07, 2014, 06:36:30 AM
It does work through powershell. The attached script and .ps1 file will interpret the previously posted secretdata.txt file.
Title: Re: Can CLR work with secure strings?
Post by: stanl on April 08, 2014, 05:59:09 AM
and... if anyone is interested, here is the front end, a script to build a secure string. Had to run WB through PS and beginning to wonder if this secure string stuff needs .NET 4.5
Title: Re: Can CLR work with secure strings?
Post by: Deana on April 08, 2014, 09:58:26 AM
Here is a WIL code Example to create a securestring:

Code (winbatch) Select
;***************************************************************************
;**   Create a SecureString
;**
;** Purpose:  Create a dotNet SecureString
;** Inputs:  String
;** Outputs: Displays the length of the secureString
;** Reference:
;**       REQUIRES WinBatch 2013A or newer
;**
;** Developer: Deana Falk 2014.04.07
;***************************************************************************
If Version( )< '2013A'
   Pause('Notice', 'Need 2013A or Newer Version of WinBatch')
   Exit
EndIf

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Load assemblies into the WinBatch process.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; mscorlib assembly is automatically loaded by WinBatch when the CLR is loaded.
; ObjectClrOption ('use','mscorlib, version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
ObjectClrOption("use","System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Prompt for input
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
initString = 'TestString'

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Create a class implemented by a managed assembly.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;Create a SecureString
testString = ObjectClrNew( 'System.Security.SecureString')
length = StrCharCount( initString )
for i = 0 to length-1
    ochar = ObjectClrNew( 'System.Char', Char2Num(StrSub( initString, i, 1 )) )
    testString.AppendChar(ochar)
next
length = testString.Length
testString.MakeReadOnly
Pause(testString.ToString(), Length)

Exit
Title: Re: Can CLR work with secure strings?
Post by: Deana on April 08, 2014, 10:22:43 AM
Here is another code sample that tries to convert the input string back using System.Runtime.InteropServices.Marshal. It appears most of the methods exposed return a pointer of type VT_INT, which seems to convert to a WIL data type VT_I4. I then pass the pointer to a UDF that attempts to read the memory from that pointer using IntControl 32. However it seems to truncate the data att he last character and I am not quite sure how to resolve this.....yet.


Code (winbatch) Select
;***************************************************************************
;**   Create a SecureString and attempt to convert it back to a string.
;**
;** Purpose:  Create a dotNet SecureString
;** Inputs:  String
;** Outputs: Displays the converted string.
;** Reference:
;**       REQUIRES WinBatch 2013A or newer
;**>>  ISSUE: It appears most of the methods exposed return a pointer of type VT_INT, which seems to convert
;**        to a WIL data type VT_I4. I then pass the pointer to a UDF that attempts to read the memory from that pointer
;**       using IntControl 32. However it seems to truncate the data att he last character and I am not quite sure how to
;**       resolve this.....yet.

;** Developer: Deana Falk 2014.04.07
;***************************************************************************
If Version( )< '2013A'
   Pause('Notice', 'Need 2013A or Newer Version of WinBatch')
   Exit
EndIf

#DefineFunction udfGetStringFromPointer(pointer)
   DebugTrace(22)
   strFromPointer=""
   ;errormode(@off)
   cValue=IntControl(32, pointer, "LONG", 0, 0)
   ;errormode(@on)
   While cValue
      strFromPointer=strFromPointer:Num2Char(cValue)
      pointer=pointer + 1
      cValue=IntControl(32, pointer, "LONG", 0,0)
   EndWhile
   Return(strFromPointer)
#EndFunction


;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Load assemblies into the WinBatch process.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; mscorlib assembly is automatically loaded by WinBatch when the CLR is loaded.
; ObjectClrOption ('use','mscorlib, version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
ObjectClrOption("use","System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Prompt for input
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;initString = '0123456789'
initString = 'TestString'

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Create a class implemented by a managed assembly.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;Create a SecureString
testString = ObjectClrNew( 'System.Security.SecureString')
length = StrCharCount( initString )
for i = 0 to length-1
    ochar = ObjectClrNew( 'System.Char', Char2Num(StrSub( initString, i, 1 )) )
    testString.AppendChar(ochar)
next
length = testString.Length
testString.MakeReadOnly
;Pause(testString.ToString(), Length)

;Note that SecureString has no members that inspect, compare, or convert the value of a SecureString. The absence of such members helps protect the value of the
;instance from accidental or malicious exposure. Use appropriate members of the System.Runtime.InteropServices.Marshal class, such as the SecureStringToBSTR method,
;to manipulate the value of a SecureString object.

;The SecureString class and its members are not visible to COM. For more information, see ComVisibleAttribute.

;When you wish to use the value stored in the SecureString object, you will have to use the Marshal class (which can be found in the System.Runtime.InteropServices namespace).
;Among other things, this class provides methods for allocating unmanaged memory and copying unmanaged memory blocks. This includes methods that will convert the contents of
;your SecureSting object into an object of type BSTR (basic string or binary string) or a block of ANSI or Unicode memory.

Marshal = ObjectClrNew("System.Runtime.InteropServices.Marshal")

; ptr Returned from the following methods is type VT INT which is not currently supported bt WinBatch
ptr = Marshal.SecureStringToGlobalAllocUnicode(testString)
;ptr = Marshal.SecureStringToGlobalAllocAnsi(testString)
;ptr = Marshal.SecureStringToBSTR(testString)
WILptr = ObjectType( 'I4', ptr )
result = udfGetStringFromPointer(WILptr)
Pause(initString, result)

Exit
Title: Re: Can CLR work with secure strings?
Post by: stanl on April 08, 2014, 10:24:42 AM
Interesting.....

This part
ochar = ObjectClrNew( 'System.Char', Char2Num(StrSub( initString, i, 1 )) )

especially.  I assume this defaults to the -plaintext option in PS.
Title: Re: Can CLR work with secure strings?
Post by: Deana on April 08, 2014, 10:28:12 AM
Quote from: stanl on April 08, 2014, 10:24:42 AM
Interesting.....

This part
ochar = ObjectClrNew( 'System.Char', Char2Num(StrSub( initString, i, 1 )) )

especially.  I assume this defaults to the -plaintext option in PS.

Actually no. That line merely creates variable (of type 'System.Char') that contains a single character. The AppendChar method is what actually creates the secure string.
Title: Re: Can CLR work with secure strings?
Post by: stanl on April 08, 2014, 01:52:10 PM
Quote from: Deana on April 08, 2014, 10:22:43 AM
Here is another code sample that tries to convert the input string back using System.Runtime.InteropServices.Marshal. It appears most of the methods exposed return a pointer of type VT_INT, which seems to convert to a WIL data type VT_I4. I then pass the pointer to a UDF that attempts to read the memory from that pointer using IntControl 32. However it seems to truncate the data att he last character and I am not quite sure how to resolve this.....yet.

Well, at least in my original posts, the .wbt code was on the right track. I tried the PtrToStringUni method in the Marshal class. Could you not use that?
Title: Re: Can CLR work with secure strings?
Post by: td on April 08, 2014, 03:17:15 PM
A few suggested mods to experiment with
Code (winbatch) Select

; Take advantage of a MSFT's largess
#DefineFunction udfGetStringFromPointer(pointer, nLen)
hBin = BinaryAlloc((nLen+1) *2)
DllCall("kernel32.dll",long:"lstrcpyW", lpbinary:hBin, long:pointer)
BinaryEodSet(hBin, (nLen+1)*2)
strResult = BinaryPeekStrW(hBin, 0, nLen*2 )
BinaryFree(hBin)
   Return(strResult)
#EndFunction


And here
Code (winbatch) Select

length = StrCharCount( initString )
for i = 1 to length  ; 1 instead of 0
    ;ochar = ObjectClrNew( 'System.Char', Char2Num(StrSub( initString, i, 1 )) )
    ochar = Char2Num(StrSub( initString, i, 1 ))
    testString.AppendChar(ui2:ochar)
next
testString.AppendChar(ui2:0)  ; Null terminate to be safe.    

Title: Re: Can CLR work with secure strings?
Post by: Deana on April 08, 2014, 07:01:44 PM
Thanks Tony! Here is the code sample that I came up with the help of your suggestions:

Code (winbatch) Select
;***************************************************************************
;**   Create a SecureString and attempt to convert it back to a WIL string.
;**
;** Purpose:  Create then Read a dotNet SecureString
;** Inputs:  String
;** Outputs: Displays the converted string.
;** Reference:
;**       REQUIRES WinBatch 2013A or newer
;**       
;**       
;** Developer: Deana Falk, Tony Deets 2014.04.08
;***************************************************************************
If Version( )< '2013A'
   Pause('Notice', 'Need 2013A or Newer Version of WinBatch')
   Exit
EndIf

;Take advantage of a MSFT's largess
; It appears most of the methods exposed return a pointer of type VT_INT, which seems to convert
; to a WIL data type VT_I4. Pass the pointer to a UDF that attempts to read the memory from that pointer
#DefineFunction udfGetStringFromPointer(pointer, nLen)
        hBin = BinaryAlloc((nLen+1) *2)
        DllCall("kernel32.dll",long:"lstrcpyW", lpbinary:hBin, long:pointer)
        BinaryEodSet(hBin, (nLen+1)*2)
        strResult = BinaryPeekStrW(hBin, 0, nLen*2 )
        BinaryFree(hBin)
   Return(strResult)
#EndFunction

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Load assemblies into the WinBatch process.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; mscorlib assembly is automatically loaded by WinBatch when the CLR is loaded.
; ObjectClrOption ('use','mscorlib, version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
ObjectClrOption("use","System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Prompt for input
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
initString = 'TestString'
initString = '01234567890'
initString = '!@#$^&*()_+'

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Create a class implemented by a managed assembly.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;Create a SecureString
testString = ObjectClrNew( 'System.Security.SecureString')
length = StrCharCount( initString )
for i = 1 to length  ; 1 instead of 0
    ;ochar = ObjectClrNew( 'System.Char', Char2Num(StrSub( initString, i, 1 )) )
    ochar = Char2Num(StrSub( initString, i, 1 ))
    testString.AppendChar(ui2:ochar)
next
testString.AppendChar(ui2:0)  ; Null terminate to be safe.   

;length = testString.Length
testString.MakeReadOnly

;Note that SecureString has no members that inspect, compare, or convert the value of a SecureString. The absence of such members helps protect the value of the
;instance from accidental or malicious exposure. Use appropriate members of the System.Runtime.InteropServices.Marshal class, such as the SecureStringToBSTR method,
;to manipulate the value of a SecureString object.

;The SecureString class and its members are not visible to COM. For more information, see ComVisibleAttribute.

;When you wish to use the value stored in the SecureString object, you will have to use the Marshal class (which can be found in the System.Runtime.InteropServices namespace).
;Among other things, this class provides methods for allocating unmanaged memory and copying unmanaged memory blocks. This includes methods that will convert the contents of
;your SecureSting object into an object of type BSTR (basic string or binary string) or a block of ANSI or Unicode memory.

Marshal = ObjectClrNew("System.Runtime.InteropServices.Marshal")

; ptr Returned from the following methods is type VT INT which is not currently supported bt WinBatch
ptr = Marshal.SecureStringToBSTR(testString)
WILptr = ObjectType( 'I4', ptr )
result = udfGetStringFromPointer(WILptr,length)
Pause(initString, result)

Exit

Title: Re: Can CLR work with secure strings?
Post by: stanl on April 10, 2014, 01:44:28 PM
If I might summarize: again, a good learning experience. In other example scripts using the CLR a property that accepted a string value could just be assigned it. In this case the securestring property needed a few hoops. Also, the method in the Marshal class to obtain the string from the memory pointer [ PtrToStringUni ] requires a WB udf.

I had a need (helping a friend) for a compiled WB script that used secure strings. I ended up with a script that used the powershell class (combining the two I posted). Today, I tested it against Deana's code with no real differences... the good part being both are WB code.  Obviously PS cmdlets hide a lot of the 'innards', and so I appreciate both Tony and Deana totally winbatching this thread....
Title: Re: Can CLR work with secure strings?
Post by: Deana on April 10, 2014, 02:05:01 PM
Quote from: stanl on April 10, 2014, 01:44:28 PM
If I might summarize: again, a good learning experience. In other example scripts using the CLR a property that accepted a string value could just be assigned it. In this case the securestring property needed a few hoops.
Actually SecureString is a "Class".  The SecureString Class expects a subarray of System.Char objects, which is NOT the same as a BSTR/WIL string. The code I posted calls the AppendChar method which appends a character to the end of the current secure string.
Reference: http://msdn.microsoft.com/en-us/library/system.security.securestring%28v=vs.110%29.aspx

Quote from: stanl on April 10, 2014, 01:44:28 PM
Also, the method in the Marshal class to obtain the string from the memory pointer [ PtrToStringUni ] requires a WB udf.
Not necessarily. That is just the solution I came up with. The Marshal Class also seems to provide a ReadByte method that you might be able to use.
Reference: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal(v=vs.100).ASPX

Title: Re: Can CLR work with secure strings?
Post by: stanl on April 12, 2014, 04:36:12 AM
Quote from: Deana on April 10, 2014, 02:05:01 PM
Actually SecureString is a "Class".


Yes, I confused property with class.