SecureZeroMemory in a managed DLL?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Luigi

    SecureZeroMemory in a managed DLL?

    // SecureZeroMem.c pp

    #include <windows.h>

    extern "C" __declspec(dlle xport) PVOID __stdcall SecureZeroMem(I N
    PVOID ptr, IN SIZE_T cnt)
    {
    return SecureZeroMemor y(ptr, cnt);
    }


    I used this code to create an unmanaged DLL with a "WIN32 Project".
    Now I have created an "Empty CLR project" in Visual C++ and all builds
    fine.



    // Caller.cs

    [DllImport("Secu reZeroMem.dll", CharSet = CharSet.Auto, SetLastError =
    true)]
    private static extern IntPtr SecureZeroMem(I ntPtr ptr, uint cnt);


    I used this P/Invoke to call WIN32 code from C#.

    What is the way I can use the C++/CLI code since I can now add the C++
    DLL as a reference to my C# project?
    Windows API will be called correctly or it's better not to use C++/CLI
    for this purpose?



    Using C++/CLI I could add the C++ project to my solution and I could
    add all to GAC in an easier way (without having to do a multifile
    assembly from the command line).


    Thanks,
    Luigi.
  • Nicholas Paldino [.NET/C# MVP]

    #2
    Re: SecureZeroMemor y in a managed DLL?

    Luigi,

    If you are using C#, then you will want to access the DLL that you
    created through the P/Invoke layer.

    Mind you, if you are reading the values from memory into C#, you are
    essentially copying the data and you have to be aware of securing that
    memory as well.

    --
    - Nicholas Paldino [.NET/C# MVP]
    - mvp@spam.guard. caspershouse.co m

    "Luigi" <newsgroupusr@g mail.comwrote in message
    news:a272eb56-a303-438a-a6e7-2ab4255715e5@c2 g2000pra.google groups.com...
    // SecureZeroMem.c pp
    >
    #include <windows.h>
    >
    extern "C" __declspec(dlle xport) PVOID __stdcall SecureZeroMem(I N
    PVOID ptr, IN SIZE_T cnt)
    {
    return SecureZeroMemor y(ptr, cnt);
    }
    >
    >
    I used this code to create an unmanaged DLL with a "WIN32 Project".
    Now I have created an "Empty CLR project" in Visual C++ and all builds
    fine.
    >
    >
    >
    // Caller.cs
    >
    [DllImport("Secu reZeroMem.dll", CharSet = CharSet.Auto, SetLastError =
    true)]
    private static extern IntPtr SecureZeroMem(I ntPtr ptr, uint cnt);
    >
    >
    I used this P/Invoke to call WIN32 code from C#.
    >
    What is the way I can use the C++/CLI code since I can now add the C++
    DLL as a reference to my C# project?
    Windows API will be called correctly or it's better not to use C++/CLI
    for this purpose?
    >
    >
    >
    Using C++/CLI I could add the C++ project to my solution and I could
    add all to GAC in an easier way (without having to do a multifile
    assembly from the command line).
    >
    >
    Thanks,
    Luigi.

    Comment

    • Pavel Minaev

      #3
      Re: SecureZeroMemor y in a managed DLL?

      On Jul 18, 3:34 pm, Luigi <newsgroup...@g mail.comwrote:
      // SecureZeroMem.c pp
      >
      #include <windows.h>
      >
      extern "C" __declspec(dlle xport) PVOID __stdcall SecureZeroMem(I N
      PVOID ptr, IN SIZE_T cnt)
      {
          return SecureZeroMemor y(ptr, cnt);
      >
      }
      >
      I used this code to create an unmanaged DLL with a "WIN32 Project".
      Now I have created an "Empty CLR project" in Visual C++ and all builds
      fine.
      >
      // Caller.cs
      >
      [DllImport("Secu reZeroMem.dll", CharSet = CharSet.Auto, SetLastError =
      true)]
      private static extern IntPtr SecureZeroMem(I ntPtr ptr, uint cnt);
      >
      I used this P/Invoke to call WIN32 code from C#.
      >
      What is the way I can use the C++/CLI code since I can now add the C++
      DLL as a reference to my C# project?
      Windows API will be called correctly or it's better not to use C++/CLI
      for this purpose?
      >
      Using C++/CLI I could add the C++ project to my solution and I could
      add all to GAC in an easier way (without having to do a multifile
      assembly from the command line).
      If you are going to use SecureZeroMemor y to clear a string from the
      memory (such as password), then consider using the standard
      System.Security .SecureString class in .NET.

      Comment

      • =?ISO-8859-1?Q?Arne_Vajh=F8j?=

        #4
        Re: SecureZeroMemor y in a managed DLL?

        Luigi wrote:
        // SecureZeroMem.c pp
        >
        #include <windows.h>
        >
        extern "C" __declspec(dlle xport) PVOID __stdcall SecureZeroMem(I N
        PVOID ptr, IN SIZE_T cnt)
        {
        return SecureZeroMemor y(ptr, cnt);
        }
        You need this because SecureZeroMemor y is inline code ?
        I used this code to create an unmanaged DLL with a "WIN32 Project".
        Now I have created an "Empty CLR project" in Visual C++ and all builds
        fine.
        >
        // Caller.cs
        >
        [DllImport("Secu reZeroMem.dll", CharSet = CharSet.Auto, SetLastError =
        true)]
        private static extern IntPtr SecureZeroMem(I ntPtr ptr, uint cnt);
        >
        I used this P/Invoke to call WIN32 code from C#.
        I can not see what you really get from SecureZeroMem in C#. You
        can not use it on managed data.

        And if you have unmanaged data in some Win32 DLL, then I think you
        should call SecureZeroMemor y in that.
        What is the way I can use the C++/CLI code since I can now add the C++
        DLL as a reference to my C# project?
        Windows API will be called correctly or it's better not to use C++/CLI
        for this purpose?
        >
        Using C++/CLI I could add the C++ project to my solution and I could
        add all to GAC in an easier way (without having to do a multifile
        assembly from the command line).
        I guess you could do that.

        Arne

        Comment

        • Pavel Minaev

          #5
          Re: SecureZeroMemor y in a managed DLL?

          On Jul 20, 12:05 am, Arne Vajhøj <a...@vajhoej.d kwrote:
          I can not see what you really get from SecureZeroMem in C#. You
          can not use it on managed data.
          Why, of course it can be used on managed data - it's still a block of
          memory, after all. So long as it's pinned first, I don't see a
          problem. You can't get a pointer to an object, of course, but you can
          get pointer to a field of an object...

          Comment

          • =?ISO-8859-1?Q?Arne_Vajh=F8j?=

            #6
            Re: SecureZeroMemor y in a managed DLL?

            Pavel Minaev wrote:
            On Jul 20, 12:05 am, Arne Vajhøj <a...@vajhoej.d kwrote:
            >I can not see what you really get from SecureZeroMem in C#. You
            >can not use it on managed data.
            >
            Why, of course it can be used on managed data - it's still a block of
            memory, after all. So long as it's pinned first, I don't see a
            problem. You can't get a pointer to an object, of course, but you can
            get pointer to a field of an object...
            I was able to google Marshal.UnsafeA ddrOfPinnedArra yElement, so
            yes it is possible.

            I still consider using it with SecureZeroMem* a weird design.

            Arne

            Comment

            • Pavel Minaev

              #7
              Re: SecureZeroMemor y in a managed DLL?

              On Jul 20, 7:04 am, Arne Vajhøj <a...@vajhoej.d kwrote:
              I was able to google Marshal.UnsafeA ddrOfPinnedArra yElement, so
              yes it is possible.
              It's even easier than that:

              char[] buffer;
              ...
              fixed (char* p = buffer)
              {
              SecureZeroMemor y((IntPtr)p, buffer.Length);
              }

              Comment

              • Luigi

                #8
                Re: SecureZeroMemor y in a managed DLL?

                I have made a class for Impersonation and I have a constructor that
                accepts SecureStrings and another one that accepts strings.
                MSDN suggests to use SecureZeroMemor y to clean memory and since it is
                an inline function I created a C++ DLL to call it from C#.
                I then used C++/CLI to have the possibility of adding it to references
                and deploying it to the GAC.
                Since it is wrong to use SecureZeroMemor y on a managed C# string what
                should I do with the C# string?
                If i convert it to a SecureString I have to use ToCharArray, but the
                string and the char array are still unsecured and unsecurely cleaned.

                Any help would be appreciated.

                Thanks,
                Luigi.

                Comment

                • Pavel Minaev

                  #9
                  Re: SecureZeroMemor y in a managed DLL?

                  On Jul 21, 4:17 pm, Luigi <newsgroup...@g mail.comwrote:
                  I have made a class for Impersonation and I have a constructor that
                  accepts SecureStrings and another one that accepts strings.
                  MSDN suggests to use SecureZeroMemor y to clean memory and since it is
                  an inline function I created a C++ DLL to call it from C#.
                  Technically, SecureZeroMemor y macro simply suppresses compiler
                  optimization (specifically, dead code removal). If you can avoid that
                  by other means (e.g. by declaring the buffer as volatile), you don't
                  need SecureZeroMemor y - you can just as well just iterate over it
                  yourself and zero all bytes.
                  I then used C++/CLI to have the possibility of adding it to references
                  and deploying it to the GAC.
                  Since it is wrong to use SecureZeroMemor y on a managed C# string what
                  should I do with the C# string?
                  Do not use C# strings for this particular task at all. Use only
                  SecureString.
                  If i convert it to a SecureString I have to use ToCharArray
                  What do you have to use it for? Can you detail what exactly you're
                  trying to do here, preferrably with code?

                  Comment

                  • Luigi

                    #10
                    Re: SecureZeroMemor y in a managed DLL?

                    What do you have to use it for? Can you detail what exactly you're
                    trying to do here, preferrably with code?
                    SecureString let me be safe but I have to create a SecureString using
                    unsafe code (char*) which I would like to avoid or prompting the user
                    for a password (and using AppendChar).
                    If I have an encrypted password in app.config, when I decrypt it I
                    have a string "at risk".
                    Now I can convert it to SecureString (using str.ToCharArray and
                    AppendChar) or pass it unencrypted trying to clean memory.


                    Till now I used this code:

                    string str = "UnicodePasswor d";
                    passwordPtr = Marshal.StringT oHGlobalUni(str );
                    //...
                    uint size = (uint)(2 * (str.Length + 1));
                    SecureZeroMem(p asswordPtr, size);
                    Marshal.FreeHGl obal(passwordPt r);


                    Many people suggested me to pin the string in memory, so I should use
                    a code like this (tell me if I'm wrong):

                    string str = "UnicodePasswor d";
                    byte[] arr = System.Text.Enc oding.Unicode.G etBytes(str);

                    // extra 2 for null terminator char on end that "C" expects
                    Array cArr = Array.CreateIns tance(typeof(by te), arr.Length + 2);
                    Array.Copy(arr, cArr, arr.Length);
                    Array.Clear(arr , 0, arr.Length);

                    GCHandle handle = GCHandle.Alloc( cArr, GCHandleType.Pi nned);
                    IntPtr passwordPtr = handle.AddrOfPi nnedObject();

                    LogonUser(userN ame, domainName, passwordPtr, logonType,
                    LOGON32_PROVIDE R_DEFAULT, out currToken);
                    SecureZeroMem(p asswordPtr, cArr.Length);

                    handle.Free();


                    The problem is that str and arr are "at risk" and also cArr until
                    SecureZeroMem is called: wouldn't be better to convert to SecureString
                    and call Array.Clear on the temporary char array?


                    Thank for your help!
                    Luigi.

                    Comment

                    • Pavel Minaev

                      #11
                      Re: SecureZeroMemor y in a managed DLL?

                      On Jul 22, 12:49 pm, Luigi <newsgroup...@g mail.comwrote:
                      SecureString let me be safe but I have to create a SecureString using
                      unsafe code (char*) which I would like to avoid
                      There's no point trying to avoid unsafe code, if the only alternative
                      is using P/Invoke - the end result is the same, since the latter is
                      also "unsafe".

                      You can also use SecureString.Ap pendChar
                      or prompting the user for a password (and using AppendChar).
                      If I have an encrypted password in app.config, when I decrypt it I
                      have a string "at risk".
                      Now I can convert it to SecureString (using str.ToCharArray and
                      AppendChar) or pass it unencrypted trying to clean memory.
                      It doesn't really matter, since as soon as you've got that first
                      System.String instance, you've already got it in memory, and will have
                      to clean it up, too...
                      Till now I used this code:
                      >
                      string str = "UnicodePasswor d";
                      passwordPtr = Marshal.StringT oHGlobalUni(str );
                      //...
                      uint size = (uint)(2 * (str.Length + 1));
                      SecureZeroMem(p asswordPtr, size);
                      Marshal.FreeHGl obal(passwordPt r);
                      This copies the string data, and then zeroes out the copy. The
                      original string remains untouched.
                      Many people suggested me to pin the string in memory, so I should use
                      a code like this (tell me if I'm wrong):
                      >
                      string str = "UnicodePasswor d";
                      byte[] arr = System.Text.Enc oding.Unicode.G etBytes(str);
                      >
                      // extra 2 for null terminator char on end that "C" expects
                      Array cArr = Array.CreateIns tance(typeof(by te), arr.Length + 2);
                      Array.Copy(arr, cArr, arr.Length);
                      Array.Clear(arr , 0, arr.Length);
                      >
                      GCHandle handle = GCHandle.Alloc( cArr, GCHandleType.Pi nned);
                      IntPtr passwordPtr = handle.AddrOfPi nnedObject();
                      >
                      LogonUser(userN ame, domainName, passwordPtr, logonType,
                      LOGON32_PROVIDE R_DEFAULT, out currToken);
                      SecureZeroMem(p asswordPtr, cArr.Length);
                      >
                      handle.Free();
                      Same here. You zero out the array, but the string from which you have
                      created it is still there.

                      I really don't see how you can stay secure here without avoiding
                      creation of any String instances. Since they're immutable, you can't
                      really "clear" them (well technically you still can, by taking the
                      pointer to the first element and zeroing the bytes within, but
                      strictly speaking this is not guaranteed to work - mutating the string
                      is U.B.). So long as your data remains in arrays (char[] or byte[],
                      doesn't matter), you can clear it, though even there I would be
                      suspicious - keep in mind that .NET GC is compacting, so it can move
                      those arrays around - and there is no guarantee that the "move" will
                      erase the bytes from the original place. So it seems that you're stuck
                      with SecureString and using non-GC'ed memory (either stackalloc'd or
                      Marshal.Alloc*) here.

                      Comment

                      • Luigi

                        #12
                        Re: SecureZeroMemor y in a managed DLL?

                        So long as your data remains in arrays (char[] or byte[],
                        doesn't matter), you can clear it
                        So it seems that you're stuck with SecureString and using
                        non-GC'ed memory (either stackalloc'd or Marshal.Alloc*) here.
                        Could you please tell me how to create a SecureString from an
                        encrypted password in app.config?
                        Using char* and the unsafe keyword?


                        Thanks a lot!

                        Luigi.

                        Comment

                        • Pavel Minaev

                          #13
                          Re: SecureZeroMemor y in a managed DLL?

                          On Jul 22, 1:36 pm, Luigi <newsgroup...@g mail.comwrote:
                          Could you please tell me how to create a SecureString from an
                          encrypted password in app.config?
                          Using char* and the unsafe keyword?
                          If having encrypted password in memory is okay for you, then you read
                          it into plain string with the usual means, create a blank
                          SecureString, and then decrypt the encrypted string character by
                          character, adding the decrypted chars to a SecureString using
                          AppendChar. Since you did not say how exactly your string is
                          encrypted, I cannot be more specific here. If you can give more
                          details on the nature of encryption, I'll come up with the code.

                          If having password, even encrypted, uncleared is not okay, then you
                          will essentially have to write your own parser for app.config from
                          scratch (including parsing XML). Here's why: all existing .NET parsers
                          use plain strings internally, and can cache them arbitrarily - you
                          have no way to know, and cannot rely on that behavior anyway. So using
                          e.g. XmlReader (or anything higher-level) would leave your strings
                          exposed.

                          But then again, if encrypted password is okay in app.config, there's
                          no point in trying to secure it in memory.

                          Comment

                          • Luigi

                            #14
                            Re: SecureZeroMemor y in a managed DLL?

                            decrypt the encrypted string character by character, adding the decrypted chars to a SecureString using
                            AppendChar.
                            I will use System.Security .Cryptography.P rotectedData to use DPAPI/
                            Protected Storage or Triple DES.
                            I do not know if Triple DES is a good choice, but I would like to be
                            able to deploy the app.config to many machines without having to
                            encrypt again passwords each time as with DPAPI and no one has told me
                            wich is the best practice in this case.

                            if encrypted password is okay in app.config, there's no point in trying to secure it in memory.
                            Why it doesn't make any sense?
                            There is no risk in memory?
                            When I need to use that password to call LogonUser it would be better
                            if no one can read it from memory... am I wrong?


                            Thanks,
                            Luigi.

                            Comment

                            • Pavel Minaev

                              #15
                              Re: SecureZeroMemor y in a managed DLL?

                              On Jul 22, 6:07 pm, Luigi <newsgroup...@g mail.comwrote:
                              I will use System.Security .Cryptography.P rotectedData to use DPAPI/
                              Protected Storage or Triple DES.
                              I do not know if Triple DES is a good choice, but I would like to be
                              able to deploy the app.config to many machines without having to
                              encrypt again passwords each time as with DPAPI and no one has told me
                              wich is the best practice in this case.
                              Where are you going to read the key to decrypt the password with?

                              And if your app has read access to that key and the config, then what
                              stops the attacker able to run your pgroam from decrypting the
                              password himself without bothering to look for it in memory?
                              if encrypted password is okay in app.config, there's no point in tryingto secure it in memory.
                              >
                              Why it doesn't make any sense?
                              There is no risk in memory?
                              There is no more risk in memory than there is on disk. Note that I
                              specifically referred to the _encrypted_ password, not the decrypted
                              one. So, to clarify: if you are okay in keeping encrypted password in
                              memory (in exactly the same form as it is in app.config), and only
                              securely erasing decrypted password as soon as you've used it, then it
                              seems it can be done in an easy way.

                              Comment

                              Working...