51

I want the text entered in the textbox to be converted to securestring in c#.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Indish Cholleti
  • 887
  • 3
  • 11
  • 21
  • 8
    Wouldn't a _PasswordBox_ and the _SecurePassword_ property be more appropriate than a _TextBox_ for entering a **password**? Using a _SecureString_ won't really help if the password is stored as a string property of the TextBox... _PasswordBox_ on the other hand uses SecureString (or similar) internally.. – flindeberg Mar 27 '12 at 11:57
  • 2
    @hamad as others have pointed out, google leads here. Given that SO is a good resource for these things, we all click here first. Once it's been asked, it's not constructive to point people back to Google. – BrainSlugs83 Jun 23 '16 at 18:32
  • 3
    For googlers, the most concise answer I found in comments: `var output = new SecureString(); input.ToList().ForEach(output.AppendChar);`. – BrainSlugs83 Jun 23 '16 at 18:44

7 Answers7

88

The simplest approach is to iterate over the source string and append one character at a time to the secure string, like so:

var secure = new SecureString();
foreach (char c in textbox1.Text)
{
    secure.AppendChar(c);
}
Jake
  • 7,565
  • 6
  • 55
  • 68
Balazs Tihanyi
  • 6,659
  • 5
  • 23
  • 24
  • 22
    Note that keeping the data in a plain string before being converted to SecureString beats the whole point of using SecureString. – Péter Török Feb 17 '14 at 10:52
  • 7
    Google leads here. Internet answers referring to google are the most circular thing imaginable. If the question has already been asked on SO, that's another matter (and I'm sure it has). – Josh Sutterfield Feb 25 '16 at 00:03
  • 9
    Am I the only one who finds it bewildering that the single most common `SecureString` use case requires a for loop? – Jake Aug 19 '16 at 19:22
  • @PéterTörök Indeed. However, things like the SqlConnection constructor taking an SqlCredential parameter has no other option than passing the password as a SecureString - so one is forced to use an insecure SecureString in this manner. – Joe Dyndale May 23 '17 at 06:44
  • @JoeDyndale , better to save `SqlCredential` parameter in `My.Settings` (Application Settings/Config file), while encrypting the setting file . _[so there is other option](https://stackoverflow.com/a/29177724/7735285)_. **Never use password coded in anyway**, according to MS its recoverable with some tools after deploy [Security Note](https://msdn.microsoft.com/en-us/library/h83s4e12(v=vs.110).aspx). – wpcoder Aug 04 '17 at 23:16
  • @wpcoder You mean I initially, before deploying the web app, have to serialize the SqlCredential instance to a settings file and then deserialize it from there in the live app? That seems very strange. – Joe Dyndale Aug 07 '17 at 08:53
  • @JoeDyndale , Please find time to read this article, its long read, but essential. [Encrypting Configuration Information Using Protected Configuration](https://msdn.microsoft.com/library/51cdfe5b-9d82-458c-94ff-c551c4f38ed1). – wpcoder Aug 07 '17 at 10:16
  • @wpcoder Thanks. I had a quick look, and will definitely go through that article. However, it doesn't really solve the issue at hand regarding SecureString... When the password is loaded from web.config it will still have to be stored locally in, say, a string variable, before being converted to a SecureString. So the issue Péter Török mentioned still applies. – Joe Dyndale Aug 07 '17 at 12:17
  • @PéterTörök Could you enlighten me on how to do it the right way please? – Ozkan Aug 28 '18 at 11:41
34

Invent once and reuse lots. Create a simple extension method to extend the string base class and store it some static utilities class somewhere

using System.Security;

/// <summary>
/// Returns a Secure string from the source string
/// </summary>
/// <param name="Source"></param>
/// <returns></returns>
public static SecureString ToSecureString(this string source)
{
    if (string.IsNullOrWhiteSpace(source))
        return null;
    else
    {
        SecureString result = new SecureString();
        foreach (char c in source.ToCharArray())
            result.AppendChar(c);
        return result;
    }
}

and then call as follows:

textbox1.Text.ToSecureString();
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Colin Gardner
  • 531
  • 5
  • 5
  • 12
    Note that keeping the data in a plain string before being converted to SecureString beats the whole point of using SecureString. – Péter Török Feb 17 '14 at 10:52
  • 1
    I would return an empty `SecureString` if the string is null or white space to represent a null or empty `SecureString`. `NullReferenceExceptions` can be cruel. –  Sep 25 '16 at 17:30
18

You should make the SecureString readonly. So the code should look like this:

static class SecureStringExtensions
{
    public static string ToUnsecureString(this SecureString secureString)
    {
        if (secureString == null) throw new ArgumentNullException("secureString");

        var unmanagedString = IntPtr.Zero;
        try
        {
            unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString);
            return Marshal.PtrToStringUni(unmanagedString);
        }
        finally
        {
            Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
        }
    }

    public static SecureString ToSecureString(this string unsecureString)
    {
        if (unsecureString == null) throw new ArgumentNullException("unsecureString");

        return unsecureString.Aggregate(new SecureString(), AppendChar, MakeReadOnly);
    }

    private static SecureString MakeReadOnly(SecureString ss)
    {
        ss.MakeReadOnly();
        return ss;
    }

    private static SecureString AppendChar(SecureString ss, char c)
    {
        ss.AppendChar(c);
        return ss;
    }
}
MovGP0
  • 7,267
  • 3
  • 49
  • 42
  • 2
    Small tweak to your code is to use 'nameof(securestring)' and 'nameof(unsecureString)' when throwing the ArgumentNullExceptions. In my implementation I used lambda's for AppendChar and MakeReadOnly, but that's just personal flavour sauce ;) – Jif Feb 03 '16 at 07:43
  • That was useful. Made a bunch of minor cleanups in my own version, but I didn't know about `Marshal.SecureStringToGlobalAllocUnicode`. -- Thanks! – BrainSlugs83 Jun 23 '16 at 19:01
1

It may be a little late but you can convert SecureString to String this way either

using System.Security;
.
.
.
/// <summary>
/// Converts String to SecureString
/// </summary>
/// <param name="input">Input in String</param>
/// <returns>Input in SecureString</returns>
public SecureString String2SecureString(String input) {
    SecureString _output = new SecureString();
    input.ToCharArray().ToList().ForEach((q) => _output.AppendChar(q));
    return _output;
}

although it all the same as Balazs Tihanyi's answer:

Google is your friend...

var secure = new SecureString(); 
foreach(char c in textbox1.Text) 
{
secure.AppendChar(c); 
}
ParsaG72
  • 29
  • 1
  • 4
1

I'm supprised nobody metioned about SecureString constructor taking pointer to char array.

public static SecureString ToSecureString(this string source)
{
    char[] charArray = source.ToCharArray();
    unsafe
    {
        fixed (char* chars = charArray)
        {
            return new SecureString(chars, charArray.Length);
        }
    }
}

Note that this code only works with /unsafe compiler option. To set this option go to project properties, Build tab and check Allow unsafe code checkbox.

Szybki
  • 1,083
  • 14
  • 29
  • Can't find this option! where is it in Visual Studio 2017? what is the use? – wpcoder Aug 04 '17 at 22:51
  • @wpcoder What kind of project do you have? Windows Universal, Windows Classic Desktop or something else? – Szybki Aug 07 '17 at 11:43
  • Windows forms , I am referring to how to add `/unsafe` in vs 2017, and what is the benefits? – wpcoder Aug 07 '17 at 13:02
  • 1
    @wpcoder In VS2017 there's pretty much the same way of adding `/unsafe` parameter as in earlier VS versions - right click on your WinForms project in the `Project Explorer` and select `Properties` or double click on the `Properties` item under your WinForms project in the `Project Explorer`. Then select `Build` tab and check the `Allow unsafe code` checkbox. This will allow you to use the `unsafe { }` context which is required to use pointers in managed code. – Szybki Aug 07 '17 at 14:25
  • Thank you @Szybki , but can't find it in VS2017 CE, anyway I got what is the benefits. – wpcoder Aug 07 '17 at 15:19
  • @wpcoder `what is the use?`: If you access memory directly from C# code using pointers you should always use the `unsafe` keyword and the `fixed` keyword tells that it should not be moved in the memory. This all is used because the `SecureString` constructor is expecting a `char* (char pointer)` – Jordy van Eijk Jun 12 '18 at 12:02
1

Nearly the same, but shorter:

SecureString secureString = new SecureString();
textbox1.Text.ToCharArray().ForEach(c => secureString.AppendChar(c));
jr_gen
  • 53
  • 6
-1

use this for the event handler on your text box:

private void textbox1_TextChanged(object sender, EventArgs e)
    {
    SecureString newSecureTextBox = new SecureString();
        foreach (char c in textbox1.Text.ToCharArray())
        {
        newSecureTextBox.AppendChar(c);
        }
    }

call your variable normally as newSecureTextBox

superKing
  • 79
  • 1
  • 6
  • 14
  • 1
    A nice thought, but I think you meant `LostFocus`, not `TextChanged`. Everytime a key is pressed the TextChanged event fires, so it's rebuilding each time as they would be trying to type a keystroke. And why `.ToCharArray()`? You can get the chars from the `.Text` just fine. – vapcguy Jan 24 '17 at 21:45