Security risks from trimming a salt - c#

So I recently created a static class for password related methods and had to make a method that generated a secure salt.
Initially I implemented RNGCryptoServiceProvider and filed n bytes into an array, which I converted to base64 and returned.
The issue was that with the output length, after conversion of course it was longer than n (which makes sense).
To fix this I changed the function to the method below, and I was just wondering if by trimming the base64 string any security risks are raised?
/// <summary>
/// Generates a salt for use with the Hash method.
/// </summary>
/// <param name="length">The length of string to generate.</param>
/// <returns>A cryptographically secure random salt.</returns>
public static string GenerateSalt(int length)
{
// Check the length isn't too short.
if (length < MIN_LENGTH)
{
throw new ArgumentOutOfRangeException("length", "Please increase the salt length to meet the minimum acceptable value of " + MIN_LENGTH + " characters.");
}
// Calculate the number of bytes required.
// https://en.wikipedia.org/wiki/Base64#Padding
// http://stackoverflow.com/questions/17944/how-to-round-up-the-result-of-integer-division
int bytelen = ((3 * length) + 4 - 1) / 4;
// Create our empty salt array.
byte[] bytes = new byte[bytelen];
// Where we'll put our generated salt.
string salt;
// Generate a random secure salt.
using (RNGCryptoServiceProvider randcrypto = new RNGCryptoServiceProvider())
{
// Fill our array with random bytes.
randcrypto.GetBytes(bytes);
// Get a base64 string from the random byte array.
salt = GetBase64(bytes);
}
// Trim the end off only if we need to.
if (salt.Length > length)
{
// Substring is the fastest method to use.
salt = salt.Substring(0, length);
}
// Return the salt.
return salt;
}
Also as a side question, I was having a quick look around and couldn't actually find what the hash function of the C# implementation of RNGCryptoServiceProvider actually is. Anyone know offhand?

Why is the length of the salt so important to you? I wouldn't think that there are any real security implication, since the only real requirement of a salt is that it be random and unguessable.
In other words, go for it.
EDIT: Here is another way of doing it using Linq.
Random random = new Random();
int length = 25; // Whatever length you want
char[] keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890!£$%^&*()".ToCharArray(); // whatever chars you want
var salt = Enumerable
.Range(1, length) // equivalent to the loop bit, for(i.. )
.Select(k => keys[random.Next(0, keys.Length - 1)]) // generate a new random char
.Aggregate("", (e, c) => e + c); // join them together into a string

There is no security risk with that way of generating the salt.
The salt doesn't need that level of security at all, it's just there so that rainbow tables can't be used to crack the hash/encryption. The regular Random class would be enough to create a salt.
Example:
/// <summary>
/// Generates a salt for use with the Hash method.
/// </summary>
/// <param name="length">The length of string to generate.</param>
/// <returns>A random salt.</returns>
public static string GenerateSalt(int length) {
// Check the length isn't too short.
if (length < MIN_LENGTH) {
throw new ArgumentOutOfRangeException("length", "Please increase the salt length to meet the minimum acceptable value of " + MIN_LENGTH + " characters.");
}
// Where we'll put our generated salt.
StringBuilder salt = new StringBuilder(length);
// Fill our string with random characters.
Random rnd = new Random();
string chars = "0123456798ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < length; i++) {
salt.Append(chars[rnd.Next(chars.Length)]);
}
// Return the salt.
return salt.ToString();
}
Note: If the function would be used more than once close in time, you would use a single Random object and pass into the function, as Random instances created too close in time will give the same random sequence.

Just for fun, here is a much faster way of doing it (even though the code doesn't look great). Try cutting and pasting this to see. On my machine it executed in about 1.6s compared to 7.1s. Since I was doing a million iterations in each case, I don't think the execution time is that important!
string msg = "";
int desiredLength = 93; // Length of salt required
Stopwatch watch = new Stopwatch();
watch.Start();
for (int k=0; k<1000000; k++)
{
double guidsNeeded = Math.Ceiling(desiredLength / 36.0);
string salt = "";
for (int i=0; i<guidsNeeded; i++)
{
salt += Guid.NewGuid().ToString();
}
salt = salt.Substring(0,desiredLength);
}
msg += watch.ElapsedMilliseconds.ToString(); // 1654 ms
watch.Start();
for (int j=0; j<1000000; j++)
{
GenerateSalt(93);
}
msg += "\r\n" + watch.ElapsedMilliseconds.ToString(); // 7096 ms
This is using Guffa's code for GenerateSalt.

Related

How to generate unique hexadecimal string up to specify characters long

I want to generate so many random unique hexadecimal value by a method.
I want to specify the character length in the parameter of this method.
public string GenerateUniqueHexadecimal(int length)
{
string date = DateTime.Now.ToString("yyMMddHHmmss");
long l = Convert.ToInt64(date);
string hex = l.ToString("X2");
hex = hex.Substring(0, length);
return hex;
}
You could create a randomized hex string like this:
public class StringRandomizer
{
public const string StringChars = "0123456789abcdef";
public string GenerateUniqueHexString(int length)
{
Random rand = new Random();
var charList = StringChars.ToArray();
string hexString = "";
for(int i = 0; i < length; i++)
{
int randIndex = rand.Next(0, charList.Length);
hexString += charList[randIndex];
}
return hexString;
}
}
If you want unique strings then they are not perfectly random -- perfectly random strings may repeat. So you can use a non-random method instead of a random method. One possibility is encryption. Use a block cipher with the right bit size and encrypt the numbers 0, 1, 2, 3, ... for as many unique outputs as you need. Because encryption is one-to-one, you are guaranteed unique outputs as long as the inputs are unique and the key stays the same. The encrypted numbers will appear random, though they are not.
For 64 bits, 16 hex characters, use DES. For 128 bits, 32 hex characters, use AES. For other sizes either use Hasty Pudding cipher, or write a version of the Feistel cipher with the required block size. That last will not be as secure as DES or AES, though that only matters if you require a high level of security.
Well, you have two main possibilities: shuffle when we create all possible Pow(16, length) hexadecimal strings, shuffle and take count of them:
using System.Linq;
...
private static Random s_Generator = new Random();
private static String[] RandomUniqueHexShuffle(int length, int count) {
return Enumerable
.Range(0, 1 << (4 * length))
.OrderBy(i => s_Generator.NextDouble())
.Take(count)
.Select(item => item.ToString($"x{length}"))
.ToArray();
}
And direct generation: where we just create string after string checking them for being unique:
private static String[] RandomUniqueHexDirect(int length, int count) {
HashSet<string> used = new HashSet<string>();
string[] result = new string[count];
for (int i = 0; i < result.Length; ) {
string value = string.Concat(Enumerable
.Range(0, length)
.Select(j => s_Generator.Next(0, 16).ToString("x")));
if (used.Add(value))
result[i++] = value;
}
return result;
}
Which of them should be chosen? For small length and large count use shuffle, otherwise - direct generation
Demo:
// unique random hex strings of length 3 (5 of them)
Console.WriteLine(string.Join(Environment.NewLine, RandomUniqueHexShuffle(3, 5)));
Console.WriteLine();
// unique random hex strings of length 24 (4 of them)
Console.WriteLine(string.Join(Environment.NewLine, RandomUniqueHexShuffle(24, 4)));
Outcome: (may vary since these are random strings)
f6b
106
baf
412
443
b150ab7c723caceccdd6b597
e3c9a9ab066dcea9ae68031c
0b2e1b368e17ed1d88c3600e
33bdf06b109f6b953f5ed2bd

Why my encrypt algorithm always returns same salt every time? [duplicate]

This question already has answers here:
Random.Next returns always the same values [duplicate]
(4 answers)
Closed 6 years ago.
I have made my own encrypt and decrypt algorithm, but if I call crypting class and encrypt data, it writes every time same salt to file, but if I start app again, the salt is different. Here are 2 application runs and its salts.
50|Mmlv"!QM17=#QwjT`11(f&}G14[bxNpN19"V+W_r`
41|Mmlv"!QM17=#QwjT`6(f&}G6[bxNpN14"V+W_r`15j.zVN6<|N-}
92|Mmlv"!QM
93|Mmlv"!QM
92|Mmlv"!QM91=#QwjT`93(f&}G
86|Mmlv"!QM88=#QwjT`
91|Mmlv"!QM93=#QwjT`
93|Mmlv"!QM
Second
50!qKR}H!;15#X:y/O`11{Q'b|1TL[PYecoj19?*V`E|L?-
41!qKR}H!;17#X:y/O`6{Q'b|6TL[PYecoj14?*V`E|L?-15M|;:Goln6&.E:yy=>
92!qKR}H!;
93!qKR}H!;
92!qKR}H!;91#X:y/O`93{Q'b|
87!qKR}H!;93#X:y/O`
86!qKR}H!;93#X:y/O`
87!qKR}H!;88#X:y/O`
And here's my encrypt code in C#
public string encryptString(string text)
{
Random rdn = new Random();
String[] textArray = new String[] { text };
string alphabet = "qzwxecrvtbynumiopalskdjfhgPMONIBUVYCTXRZEWQASLKDFJHG~!##$%^&*()_+}{|\":><?`-=][\';/., 9632587410";
string hashedText = "";
for (int i = 0; i < text.Length; i++)
{
string salt = "";
int saltCount = rdn.Next(low_range, high_range);
for (int e = 0; e < saltCount; e++)
{
int alphabetSaltCount = rdn.Next(0, alphabet.Length - 11);
salt += alphabet[alphabetSaltCount];
}
hashedText += alphabet.IndexOf(text[i]).ToString() + salt;
}
return hashedText;
}
You may need to seed the random number generator differently.
Random uses the system clock by default for its seed so calling new Random() really close to each other can end up with the same seed number.
See the section "Instantiating the random number generator" here: https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx

using RNGCryptoServiceProvider to generate random string

I'm using this code to generate random strings with given length
public string RandomString(int length)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder res = new StringBuilder();
Random rnd = new Random();
while (0 < length--)
{
res.Append(valid[rnd.Next(valid.Length)]);
}
return res.ToString();
}
However, I read that RNGCryptoServiceProvideris more secure than Random class. How can I implement RNGCryptoServiceProvider to this function. It should use valid string just like this function.
Since RNGRandomNumberGenerator only returns byte arrays, you have to do it like this:
static string RandomString(int length)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder res = new StringBuilder();
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
byte[] uintBuffer = new byte[sizeof(uint)];
while (length-- > 0)
{
rng.GetBytes(uintBuffer);
uint num = BitConverter.ToUInt32(uintBuffer, 0);
res.Append(valid[(int)(num % (uint)valid.Length)]);
}
}
return res.ToString();
}
Note however that this has a flaw, 62 valid characters is equal to 5,9541963103868752088061235991756 bits (log(62) / log(2)), so it won't divide evenly on a 32 bit number (uint).
What consequences does this have?
As a result, the random output won't be uniform. Characters which are lower in value will occur more likely (just by a small fraction, but still it happens).
To be more precise, the first 4 characters of a valid array are 0,00000144354999199840239435286 % more likely to occur.
To avoid this, you should use array lengths that will divide evenly into 64 (Consider using Convert.ToBase64String on the output instead, since you can cleanly match 64 bits to 6 bytes.
You need to generate random bytes using RNGCryptoServiceProvider and append only the valid ones to the returned string:
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
static string GetRandomString(int length)
{
string s = "";
using (RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider())
{
while (s.Length != length)
{
byte[] oneByte = new byte[1];
provider.GetBytes(oneByte);
char character = (char)oneByte[0];
if (valid.Contains(character))
{
s += character;
}
}
}
return s;
}
You could also use modulo in order to not skip the invalid byte values but that the chances for each character won't be even.
The RNGCryptoServiceProvider returns random numbers in the form of bytes, so you need a way to get a more convenient random number from it:
public static int GetInt(RNGCryptoServiceProvider rnd, int max) {
byte[] r = new byte[4];
int value;
do {
rnd.GetBytes(r);
value = BitConverter.ToInt32(r, 0) & Int32.MaxValue;
} while (value >= max * (Int32.MaxValue / max));
return value % max;
}
Then you can use that in your method:
public static string RandomString(int length) {
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder res = new StringBuilder();
using (RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider()) {
while (length-- > 0) {
res.Append(valid[GetInt(rnd, valid.Length)]);
}
}
return res.ToString();
}
(I made the method static, as it doesn't use any instance data.)
Note
I am aware of the deviation with OP's use case, but I think this might help others who does not have the "arbitrary" 62 character limitation and just want to encode bytes using RNGCryptoServiceProvider to generate random string.
TL;DR
just skip to the bottom, the base64 encoded case.
A lot can be said about the reasons to convert a cryptographic byte array into a string, but usually it is for some sort of serialization purposes; and hence, in that case: the selected character set is arbitrary.
So, if it is about serialization, you have tons of options; e.g:
text as HEX representation
text as base64 representation
text as alternative representation
All of these are making use of the same thing: encode numbers in such a way it is suited to be transmitted in a medium that does not support native binary transfer.
I call this "text as ... representation", because in the end, it is text that will be transmitted.
An example in HEX:
//note: using text as HEX makes the result longer
var crypt = new RNGCryptoServiceProvider();
var sb = new StringBuilder();
var buf = new byte[10]; //length: should be larger
crypt.GetBytes(buf);
//gives a "valid" range of: "0123456789ABCDEF"
foreach (byte b in buf)
sb.AppendFormat("{0:x2}", b); //applies "text as hex" encoding
//sb contains a RNGCryptoServiceProvider based "string"
Now you'll say:
but wait: these are only 16 characters where OP's sequence has 62. 62 is more efficient than 16, so, converted to text, your string will be a lot longer.
"Yes", I'll say, "and if that's a problem, why don't you pick a larger number easy-to-read-and-serrializable-characters... 62 ... or 64 perhaps"
The code would be:
//note: added + and / chars. could be any of them
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+/";
var crypt = new RNGCryptoServiceProvider();
var sb = new StringBuilder();
var buf = new byte[10]; //length: should be larger
crypt.GetBytes(buf); //get the bytes
foreach (byte b in buf)
sb.Append(valid[b%64]);
Note: As #Guffa stated; using % is forbidden unless it doesn't alter the distribution. To make this happen, given a evenly distributed set, the subset must fit exactly x times in the original set.
So, expanding your initial valid set with 2 gives a valid result (because: 256 / 64 = 4) --- but, this does not honor OP's 62 character requirements. In fact to get an even distribution you'll need some trickery, addressed in the other answers.
Also note: in all the answers, including this one, the sub-set is smaller than the 256 possibilities of the byte. This means there is less information available in an encoded char than in a byte. This means if you have your string with 4 encoded chars, it's easier to crack the original 4 byte result of the RNGCryptoServiceProvider - So keep in mind, the cryptographic strength is depending on the byte length, not the encoded char length.
Base64
But, now you say:
"Ok, let drop the 62 requirement, and use 64 - why not use 64 base encoding?",
well, if it's suits you, but note trailing =, see Base64 on Wikipedia, it is an additional optional charater which is used.
var crypt = new RNGCryptoServiceProvider();
// = padding characters might be added to make the last encoded block
// contain four Base64 characters.
// which is actually an additional character
var buf = new byte[10];
crypt.GetBytes(buf);
//contains a RNGCryptoServiceProvider random string, which is fairly readable
//and contains max 65 different characters.
//you can limit this to 64, by specifying a different array length.
//because log2(64) = 6, and 24 = 4 x 6 = 3 x 8
//all multiple of 3 bytes are a perfect fit. (e.g.: 3, 6, 15, 30, 60)
string result = Convert.ToBase64String(buf);
My implementation that fixes the issue with 5,9541963103868752088061235991756 bits
public static string RandomString(int length)
{
const string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
var res = new StringBuilder(length);
using (var rng = new RNGCryptoServiceProvider())
{
int count = (int)Math.Ceiling(Math.Log(alphabet.Length, 2) / 8.0);
Debug.Assert(count <= sizeof(uint));
int offset = BitConverter.IsLittleEndian ? 0 : sizeof(uint) - count;
int max = (int)(Math.Pow(2, count*8) / alphabet.Length) * alphabet.Length;
byte[] uintBuffer = new byte[sizeof(uint)];
while (res.Length < length)
{
rng.GetBytes(uintBuffer, offset, count);
uint num = BitConverter.ToUInt32(uintBuffer, 0);
if (num < max)
{
res.Append(alphabet[(int) (num % alphabet.Length)]);
}
}
}
return res.ToString();
}
see https://bitbucket.org/merarischroeder/number-range-with-no-bias/
I'm sure I have answered this one before with a secure implementation, no bias, and good performance. If so, please comment.
Looking at Tamir's answer, I thought it would be better to use the modulus operation, but trim off the incomplete remainder of byte values. I'm also writing this answer now (possibly again), because I need to reference this solution to a peer.
Approach 1
Support for ranges that are no bigger than 0-255. But it can fall back to approach 2 (which is a little slower)
One byte is always used per value.
Truncate the incomplete remainder if (buffer[i] >= exclusiveLimit)
Modulate the desired range size. After truncation beyond the exclusiveLimit the modulus remains perfectly balanced
(Using a bitmask instead of modulus is a slower approach)
EG. If you want a range 0-16 (that's 17 different values), then 17 can fit into a byte 15 times. There is 1 value that must be discarded [255], otherwise the modulus will be fine.
Code for Approach 1
const string lookupCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
static void TestRandomString()
{
Console.WriteLine("A random string of 100 characters:");
int[] randomCharacterIndexes = new int[100];
SecureRangeOriginal(randomCharacterIndexes, lookupCharacters.Length);
var sb = new StringBuilder();
for (int i = 0; i < randomCharacterIndexes.Length; i++)
{
sb.Append(lookupCharacters[randomCharacterIndexes[i]]);
}
Console.WriteLine(sb.ToString());
Console.WriteLine();
}
static void SecureRangeOriginal(int[] result, int maxInt)
{
if (maxInt > 256)
{
//If you copy this code, you can remove this line and replace it with `throw new Exception("outside supported range");`
SecureRandomIntegerRange(result, 0, result.Length, 0, maxInt); //See git repo for implementation.
return;
}
var maxMultiples = 256 / maxInt; //Finding the byte number boundary above the provided lookup length - the number of bytes
var exclusiveLimit = (maxInt * maxMultiples); //Expressing that boundary (number of bytes) as an integer
var length = result.Length;
var resultIndex = 0;
using (var provider = new RNGCryptoServiceProvider())
{
var buffer = new byte[length];
while (true)
{
var remaining = length - resultIndex;
if (remaining == 0)
break;
provider.GetBytes(buffer, 0, remaining);
for (int i = 0; i < remaining; i++)
{
if (buffer[i] >= exclusiveLimit)
continue;
var index = buffer[i] % maxInt;
result[resultIndex++] = index;
}
}
}
}
Approach 2
Technically ranges from 0 to ulong.Max can be supported
Treat RNGCryptoServiceProvider bytes as a bitstream
Calculate the base2 bit length needed per number
Take the next number from the random bitstream
If that number is still greater than the desired range, discard
Results:
See the repository for the latest results from the test harness
Both approaches appear to have a suitably balanced distribution of numbers
Approach 1 is faster [859ms] but it only works on individual bytes.
Approach 2 is a little slower [3038ms] than Approach 1, but it works across byte boundaries. It discards fewer bits, which can be useful if the random stream input becomes a bottleneck (different algorithm for example).
A hybrid of both approaches gives the best of both worlds: better speed when the byte range is 0-255, support for ranges beyond 255 but a bit slower.
I personally like to use this:
private static string GenerateRandomSecret()
{
var validChars = Enumerable.Range('A', 26)
.Concat(Enumerable.Range('a', 26))
.Concat(Enumerable.Range('0', 10))
.Select(i => (char)i)
.ToArray();
var randomByte = new byte[64 + 1]; // Max Length + Length
using (var rnd = new RNGCryptoServiceProvider())
{
rnd.GetBytes(randomByte);
var secretLength = 32 + (int)(32 * (randomByte[0] / (double)byte.MaxValue));
return new string(
randomByte
.Skip(1)
.Take(secretLength)
.Select(b => (int) ((validChars.Length - 1) * (b / (double) byte.MaxValue)))
.Select(i => validChars[i])
.ToArray()
);
}
}
There shouldn't be any part that needs additional description, but to clarify, this function returns a random string with a random length between 32 and 64 chars and doesn't use % (mod) therefore should keep uniformity a little better.
I use this to create a random salt at program installation and later save it to a file. Therefore security of generated string is not of special concern while the program is running as it is going to get written to an unencrypted file later on anyway.
However, for more serious situations, this shouldn't be used as it is and should be converted to use SecureString class if you are going to keep this value in memory. Read more here:
https://learn.microsoft.com/en-us/dotnet/api/system.security.securestring?redirectedfrom=MSDN&view=netframework-4.7.2
However, even this only applies to NetFramework, for NetCore you need to find another way to secure the value in the memory. Read more here:
https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
RNGCryptoServiceProvider is deprecated in .NET 6
Instead, its base class RandomNumberGenerator should be used.
Based on Guffa's answer a solution can be crafted like this:
public static string GetString(int length, string alphabet)
{
var secret = new StringBuilder();
while (length-- > 0)
{
secret.Append(alphabet[RandomNumberGenerator.GetInt32(alphabet.Length)]);
}
return secret.ToString();
}
Whereas alphabet is the desired set of valid characters.
private string sifreuretimi(int sayı) //3
{
Random rastgele = new Random();
StringBuilder sb = new StringBuilder();
char karakter1 = ' ', karakter2 = ' ', karakter3 = ' ';
int ascii1, ascii2, ascii3 = 0;
for (int i = 0; i < sayı/3; i++)
{
ascii1 = rastgele.Next(48,58);
karakter1 = Convert.ToChar(ascii1);
ascii2 = rastgele.Next(65, 91);
karakter2 = Convert.ToChar(ascii2);
ascii3 = rastgele.Next(97, 123);
karakter3 = Convert.ToChar(ascii3);
sb.Append(karakter1);
sb.Append(karakter2);
sb.Append(karakter3);
}
return sb.ToString();
}
This is a nice short solution that will also do the trick, if your goal is just to create a random string, let's say for use as a secure token.
public string RandomTokenString(int tokenLength)
{
var rngCryptoServiceProvider = new RNGCryptoServiceProvider();
var randomBytes = new byte[tokenLength];
rngCryptoServiceProvider.GetBytes(randomBytes);
return BitConverter.ToString(randomBytes);
}

Generate password using a for loop

I am making a password generator that generates a random number, then I have it converted to a letter using ascii. Inside the for loop, I need the letters to convert a string instead of a list. It works, but it just displays random letters as a list.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
class MainClass
{
static void Main()
{
int x = 1;
int length;
string a = "Press any key to continue";
object num;
while (x == 1)
{
Console.WriteLine("How many Characters would you like the Password to be? (Press -1 to Stop)");
length = Convert.ToInt32(Console.ReadLine());
try
{
for (int i = 0; i < length; i++)
{
int num1 = Number();
Int32 ASCII = num1;
num = (char)num1;
if (length > 0)
{
Console.WriteLine(num);
}
}
}
catch
{
Console.WriteLine(a);
}
if (length == -1)
break;
}
}
static Random _r = new Random();
static int Number()
{
return _r.Next(65, 90); // decimal
}
}
StringBuilder sb = new StringBuilder();
for( int i = 0; i < length; i++ )
{
int num1 = Number();
Int32 ASCII = num1;
num = (char)num1;
sb.Append( num );
}
Console.WriteLine( sb.ToString() );
This isn't how I would build a password nor how I would generate random text, but this will give you a string and answer the original question.
As to how I would do this task:
System.Security.Cryptography.RNGCryptoServiceProvider _crypto = new System.Security.Cryptography.RNGCryptoServiceProvider();
byte[] bytes = new byte[8]; // this array can be larger if desired
_crypto.GetBytes( bytes );
ulong randomNumber = (ulong)BitConverter.ToInt64( bytes, 0 );
// convert to a string with the encoding of your choice; I prefer Base 62
For completeness sake, here's a Base62 algorithm which I use. Base62 has the advantage over the more commonly-used Base64 in that it does not include any special characters so it is easy to use in query strings, HTML, and JavaScript (with a few minor caveats). Of course, passwords shouldn't be used in any of those places, and you may want to include special characters to make a password more complex.
Regardless, here is how I convert random numbers to Base62.
private static readonly char[] _base62Characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
public static string ToBase62String( long value )
{
if( value < 0L )
{
throw new ArgumentException( "Number must be zero or greater." );
}
if( value == 0 )
{
return "0";
}
string retVal = "";
while( value > 0 )
{
retVal = _base62Characters[value % 62] + retVal;
value = value / 62;
}
return retVal;
}
Lastly, I want to point out that passwords should very rarely be generated for any purpose, because that means they are being distributed in some form. Passwords should be hashed and salted; password resets should rely on random, expiring security tokens allowing the user a one-time reset. Passwords should never be emailed to a user; passwords should never be stored in plaintext or any reversible format.
For password reset token generation, the code I provided could work nicely because it produces a large, cryptographically random number encoded with a web-safe format. But even a hashed GUID would do the trick in that case.
var sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.Append((char)Number());
}
string password = sb.ToString();
Console.WriteLine(password );
But I would change your Number() method to:
private static char GetRandomChar()
{
return (char)_r.Next(65, 90);
}
and then replace the line inside the loop:
sb.Append(GetRandomChar());
//You have to append the values generated by the RandomNumber in to your password variable
class MainClass
{
static void Main()
{
int x = 1;
int length;
string a = "Press any key to continue";
string num=string.Empty;
while (x == 1)
{
Console.WriteLine("How many Characters would you like the Password to be? (Press -1 to Stop)");
length = Convert.ToInt32(Console.ReadLine());
try
{
for (int i = 0; i < length; i++)
{
int num1 = Number();
Int32 ASCII = num1;
num =num+ ((char)num1);
}
Console.WriteLine(num);
}
catch
{
Console.WriteLine(a);
}
if (length == -1)
break;
}
}
static Random _r = new Random();
static int Number()
{
return _r.Next(65, 90); // decimal
}
}
you can try this one
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PasswordSample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Generated password: {0}", GeneratePassword(12, true));
}
/// <summary>
/// Generate a random password
/// </summary>
/// <param name="pwdLenght">Password lenght</param>
/// <param name="nonAlphaNumericChars">Indicates if password will include non alpha-numeric</param>
/// <returns>Return a password</returns>
private static String GeneratePassword(int pwdLenght, bool nonAlphaNumericChars)
{
// Allowed characters
String allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
if (nonAlphaNumericChars)
{
// Add non-alphanumeric chars
allowedChars += "-&##%!*$?_";
}
char[] passwordChars = new char[pwdLenght];
Random rnd = new Random();
// Generate a random password
for (int i = 0; i < pwdLenght; i++)
passwordChars[i] = allowedChars[rnd.Next(0, allowedChars.Length)];
return new String(passwordChars);
}
}
}
just define a string at near int x...
like
String Password = "";
and in the if statement appent the keyyword.
if (length > 0)
{
Console.WriteLine(num);
Password+=num
}
I found the following post useful when I had to create a method to generate a random password:
https://stackoverflow.com/a/730352/1015289
However, when I wanted to create a short 'validation' style code which would be emailed to a user to confirm their details, I wanted to restrict the validation code to only 8 characters.
For this I used the following:
string validationCoce = Guid.NewGuid().ToString().Substring(0, 8);
This would be stored in a database which also held the users email, both encrypted before being stored for security purposes.
Both the email and validation code were required to validate the users account.
Hope either of the above help?
Kind Regards, Wayne
use Console.Write() instead of Console.WriteLine() otherwise append to some string and print outside the loop

Generating Random Passwords

When a user on our site loses his password and heads off to the Lost Password page we need to give him a new temporary password. I don't really mind how random this is, or if it matches all the "needed" strong password rules, all I want to do is give them a password that they can change later.
The application is a Web application written in C#. so I was thinking of being mean and going for the easy route of using part of a Guid. i.e.
Guid.NewGuid().ToString("d").Substring(1,8)
Suggesstions? thoughts?
There's always System.Web.Security.Membership.GeneratePassword(int length, int numberOfNonAlphanumericCharacters).
public string CreatePassword(int length)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder res = new StringBuilder();
Random rnd = new Random();
while (0 < length--)
{
res.Append(valid[rnd.Next(valid.Length)]);
}
return res.ToString();
}
This has a good benefit of being able to choose from a list of available characters for the generated password (e.g. digits only, only uppercase or only lowercase etc.)
The main goals of my code are:
The distribution of strings is almost uniform (don't care about minor deviations, as long as they're small)
It outputs more than a few billion strings for each argument set. Generating an 8 character string (~47 bits of entropy) is meaningless if your PRNG only generates 2 billion (31 bits of entropy) different values.
It's secure, since I expect people to use this for passwords or other security tokens.
The first property is achieved by taking a 64 bit value modulo the alphabet size. For small alphabets (such as the 62 characters from the question) this leads to negligible bias. The second and third property are achieved by using RNGCryptoServiceProvider instead of System.Random.
using System;
using System.Security.Cryptography;
public static string GetRandomAlphanumericString(int length)
{
const string alphanumericCharacters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789";
return GetRandomString(length, alphanumericCharacters);
}
public static string GetRandomString(int length, IEnumerable<char> characterSet)
{
if (length < 0)
throw new ArgumentException("length must not be negative", "length");
if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
throw new ArgumentException("length is too big", "length");
if (characterSet == null)
throw new ArgumentNullException("characterSet");
var characterArray = characterSet.Distinct().ToArray();
if (characterArray.Length == 0)
throw new ArgumentException("characterSet must not be empty", "characterSet");
var bytes = new byte[length * 8];
new RNGCryptoServiceProvider().GetBytes(bytes);
var result = new char[length];
for (int i = 0; i < length; i++)
{
ulong value = BitConverter.ToUInt64(bytes, i * 8);
result[i] = characterArray[value % (uint)characterArray.Length];
}
return new string(result);
}
(This is a copy of my answer to How can I generate random 8 character, alphanumeric strings in C#?)
public string GenerateToken(int length)
{
using (RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider())
{
byte[] tokenBuffer = new byte[length];
cryptRNG.GetBytes(tokenBuffer);
return Convert.ToBase64String(tokenBuffer);
}
}
(You could also have the class where this method lives implement IDisposable, hold a reference to the RNGCryptoServiceProvider, and dispose of it properly, to avoid repeatedly instantiating it.)
It's been noted that as this returns a base-64 string, the output length is always a multiple of 4, with the extra space using = as a padding character. The length parameter specifies the length of the byte buffer, not the output string (and is therefore perhaps not the best name for that parameter, now I think about it). This controls how many bytes of entropy the password will have. However, because base-64 uses a 4-character block to encode each 3 bytes of input, if you ask for a length that's not a multiple of 3, there will be some extra "space", and it'll use = to fill the extra.
If you don't like using base-64 strings for any reason, you can replace the Convert.ToBase64String() call with either a conversion to regular string, or with any of the Encoding methods; eg. Encoding.UTF8.GetString(tokenBuffer) - just make sure you pick a character set that can represent the full range of values coming out of the RNG, and that produces characters that are compatible with wherever you're sending or storing this. Using Unicode, for example, tends to give a lot of Chinese characters. Using base-64 guarantees a widely-compatible set of characters, and the characteristics of such a string shouldn't make it any less secure as long as you use a decent hashing algorithm.
This is a lot larger, but I think it looks a little more comprehensive:
http://www.obviex.com/Samples/Password.aspx
///////////////////////////////////////////////////////////////////////////////
// SAMPLE: Generates random password, which complies with the strong password
// rules and does not contain ambiguous characters.
//
// To run this sample, create a new Visual C# project using the Console
// Application template and replace the contents of the Class1.cs file with
// the code below.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
//
// Copyright (C) 2004 Obviex(TM). All rights reserved.
//
using System;
using System.Security.Cryptography;
/// <summary>
/// This class can generate random passwords, which do not include ambiguous
/// characters, such as I, l, and 1. The generated password will be made of
/// 7-bit ASCII symbols. Every four characters will include one lower case
/// character, one upper case character, one number, and one special symbol
/// (such as '%') in a random order. The password will always start with an
/// alpha-numeric character; it will not start with a special symbol (we do
/// this because some back-end systems do not like certain special
/// characters in the first position).
/// </summary>
public class RandomPassword
{
// Define default min and max password lengths.
private static int DEFAULT_MIN_PASSWORD_LENGTH = 8;
private static int DEFAULT_MAX_PASSWORD_LENGTH = 10;
// Define supported password characters divided into groups.
// You can add (or remove) characters to (from) these groups.
private static string PASSWORD_CHARS_LCASE = "abcdefgijkmnopqrstwxyz";
private static string PASSWORD_CHARS_UCASE = "ABCDEFGHJKLMNPQRSTWXYZ";
private static string PASSWORD_CHARS_NUMERIC= "23456789";
private static string PASSWORD_CHARS_SPECIAL= "*$-+?_&=!%{}/";
/// <summary>
/// Generates a random password.
/// </summary>
/// <returns>
/// Randomly generated password.
/// </returns>
/// <remarks>
/// The length of the generated password will be determined at
/// random. It will be no shorter than the minimum default and
/// no longer than maximum default.
/// </remarks>
public static string Generate()
{
return Generate(DEFAULT_MIN_PASSWORD_LENGTH,
DEFAULT_MAX_PASSWORD_LENGTH);
}
/// <summary>
/// Generates a random password of the exact length.
/// </summary>
/// <param name="length">
/// Exact password length.
/// </param>
/// <returns>
/// Randomly generated password.
/// </returns>
public static string Generate(int length)
{
return Generate(length, length);
}
/// <summary>
/// Generates a random password.
/// </summary>
/// <param name="minLength">
/// Minimum password length.
/// </param>
/// <param name="maxLength">
/// Maximum password length.
/// </param>
/// <returns>
/// Randomly generated password.
/// </returns>
/// <remarks>
/// The length of the generated password will be determined at
/// random and it will fall with the range determined by the
/// function parameters.
/// </remarks>
public static string Generate(int minLength,
int maxLength)
{
// Make sure that input parameters are valid.
if (minLength <= 0 || maxLength <= 0 || minLength > maxLength)
return null;
// Create a local array containing supported password characters
// grouped by types. You can remove character groups from this
// array, but doing so will weaken the password strength.
char[][] charGroups = new char[][]
{
PASSWORD_CHARS_LCASE.ToCharArray(),
PASSWORD_CHARS_UCASE.ToCharArray(),
PASSWORD_CHARS_NUMERIC.ToCharArray(),
PASSWORD_CHARS_SPECIAL.ToCharArray()
};
// Use this array to track the number of unused characters in each
// character group.
int[] charsLeftInGroup = new int[charGroups.Length];
// Initially, all characters in each group are not used.
for (int i=0; i<charsLeftInGroup.Length; i++)
charsLeftInGroup[i] = charGroups[i].Length;
// Use this array to track (iterate through) unused character groups.
int[] leftGroupsOrder = new int[charGroups.Length];
// Initially, all character groups are not used.
for (int i=0; i<leftGroupsOrder.Length; i++)
leftGroupsOrder[i] = i;
// Because we cannot use the default randomizer, which is based on the
// current time (it will produce the same "random" number within a
// second), we will use a random number generator to seed the
// randomizer.
// Use a 4-byte array to fill it with random bytes and convert it then
// to an integer value.
byte[] randomBytes = new byte[4];
// Generate 4 random bytes.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
// Convert 4 bytes into a 32-bit integer value.
int seed = BitConverter.ToInt32(randomBytes, 0);
// Now, this is real randomization.
Random random = new Random(seed);
// This array will hold password characters.
char[] password = null;
// Allocate appropriate memory for the password.
if (minLength < maxLength)
password = new char[random.Next(minLength, maxLength+1)];
else
password = new char[minLength];
// Index of the next character to be added to password.
int nextCharIdx;
// Index of the next character group to be processed.
int nextGroupIdx;
// Index which will be used to track not processed character groups.
int nextLeftGroupsOrderIdx;
// Index of the last non-processed character in a group.
int lastCharIdx;
// Index of the last non-processed group.
int lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1;
// Generate password characters one at a time.
for (int i=0; i<password.Length; i++)
{
// If only one character group remained unprocessed, process it;
// otherwise, pick a random character group from the unprocessed
// group list. To allow a special character to appear in the
// first position, increment the second parameter of the Next
// function call by one, i.e. lastLeftGroupsOrderIdx + 1.
if (lastLeftGroupsOrderIdx == 0)
nextLeftGroupsOrderIdx = 0;
else
nextLeftGroupsOrderIdx = random.Next(0,
lastLeftGroupsOrderIdx);
// Get the actual index of the character group, from which we will
// pick the next character.
nextGroupIdx = leftGroupsOrder[nextLeftGroupsOrderIdx];
// Get the index of the last unprocessed characters in this group.
lastCharIdx = charsLeftInGroup[nextGroupIdx] - 1;
// If only one unprocessed character is left, pick it; otherwise,
// get a random character from the unused character list.
if (lastCharIdx == 0)
nextCharIdx = 0;
else
nextCharIdx = random.Next(0, lastCharIdx+1);
// Add this character to the password.
password[i] = charGroups[nextGroupIdx][nextCharIdx];
// If we processed the last character in this group, start over.
if (lastCharIdx == 0)
charsLeftInGroup[nextGroupIdx] =
charGroups[nextGroupIdx].Length;
// There are more unprocessed characters left.
else
{
// Swap processed character with the last unprocessed character
// so that we don't pick it until we process all characters in
// this group.
if (lastCharIdx != nextCharIdx)
{
char temp = charGroups[nextGroupIdx][lastCharIdx];
charGroups[nextGroupIdx][lastCharIdx] =
charGroups[nextGroupIdx][nextCharIdx];
charGroups[nextGroupIdx][nextCharIdx] = temp;
}
// Decrement the number of unprocessed characters in
// this group.
charsLeftInGroup[nextGroupIdx]--;
}
// If we processed the last group, start all over.
if (lastLeftGroupsOrderIdx == 0)
lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1;
// There are more unprocessed groups left.
else
{
// Swap processed group with the last unprocessed group
// so that we don't pick it until we process all groups.
if (lastLeftGroupsOrderIdx != nextLeftGroupsOrderIdx)
{
int temp = leftGroupsOrder[lastLeftGroupsOrderIdx];
leftGroupsOrder[lastLeftGroupsOrderIdx] =
leftGroupsOrder[nextLeftGroupsOrderIdx];
leftGroupsOrder[nextLeftGroupsOrderIdx] = temp;
}
// Decrement the number of unprocessed groups.
lastLeftGroupsOrderIdx--;
}
}
// Convert password characters into a string and return the result.
return new string(password);
}
}
/// <summary>
/// Illustrates the use of the RandomPassword class.
/// </summary>
public class RandomPasswordTest
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
// Print 100 randomly generated passwords (8-to-10 char long).
for (int i=0; i<100; i++)
Console.WriteLine(RandomPassword.Generate(8, 10));
}
}
//
// END OF FILE
///////////////////////////////////////////////////////////////////////////////
I created this class that uses RNGCryptoServiceProvider and it is flexible. Example:
var generator = new PasswordGenerator(minimumLengthPassword: 8,
maximumLengthPassword: 15,
minimumUpperCaseChars: 2,
minimumNumericChars: 3,
minimumSpecialChars: 2);
string password = generator.Generate();
I know that this is an old thread, but I have what might be a fairly simple solution for someone to use. Easy to implement, easy to understand, and easy to validate.
Consider the following requirement:
I need a random password to be generated which has at least 2 lower-case letters, 2 upper-case letters and 2 numbers. The password must also be a minimum of 8 characters in length.
The following regular expression can validate this case:
^(?=\b\w*[a-z].*[a-z]\w*\b)(?=\b\w*[A-Z].*[A-Z]\w*\b)(?=\b\w*[0-9].*[0-9]\w*\b)[a-zA-Z0-9]{8,}$
It's outside the scope of this question - but the regex is based on lookahead/lookbehind and lookaround.
The following code will create a random set of characters which match this requirement:
public static string GeneratePassword(int lowercase, int uppercase, int numerics) {
string lowers = "abcdefghijklmnopqrstuvwxyz";
string uppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string number = "0123456789";
Random random = new Random();
string generated = "!";
for (int i = 1; i <= lowercase; i++)
generated = generated.Insert(
random.Next(generated.Length),
lowers[random.Next(lowers.Length - 1)].ToString()
);
for (int i = 1; i <= uppercase; i++)
generated = generated.Insert(
random.Next(generated.Length),
uppers[random.Next(uppers.Length - 1)].ToString()
);
for (int i = 1; i <= numerics; i++)
generated = generated.Insert(
random.Next(generated.Length),
number[random.Next(number.Length - 1)].ToString()
);
return generated.Replace("!", string.Empty);
}
To meet the above requirement, simply call the following:
String randomPassword = GeneratePassword(3, 3, 3);
The code starts with an invalid character ("!") - so that the string has a length into which new characters can be injected.
It then loops from 1 to the # of lowercase characters required, and on each iteration, grabs a random item from the lowercase list, and injects it at a random location in the string.
It then repeats the loop for uppercase letters and for numerics.
This gives you back strings of length = lowercase + uppercase + numerics into which lowercase, uppercase and numeric characters of the count you want have been placed in a random order.
I'll add another ill-advised answer to the pot.
I have a use case where I need random passwords for machine-machine communication, so I don't have any requirement for human readability. I also don't have access to Membership.GeneratePassword in my project, and don't want to add the dependency.
I am fairly certain Membership.GeneratePassword is doing something similar to this, but here you can tune the pools of characters to draw from.
public static class PasswordGenerator
{
private readonly static Random _rand = new Random();
public static string Generate(int length = 24)
{
const string lower = "abcdefghijklmnopqrstuvwxyz";
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string number = "1234567890";
const string special = "!##$%^&*_-=+";
// Get cryptographically random sequence of bytes
var bytes = new byte[length];
new RNGCryptoServiceProvider().GetBytes(bytes);
// Build up a string using random bytes and character classes
var res = new StringBuilder();
foreach(byte b in bytes)
{
// Randomly select a character class for each byte
switch (_rand.Next(4))
{
// In each case use mod to project byte b to the correct range
case 0:
res.Append(lower[b % lower.Count()]);
break;
case 1:
res.Append(upper[b % upper.Count()]);
break;
case 2:
res.Append(number[b % number.Count()]);
break;
case 3:
res.Append(special[b % special.Count()]);
break;
}
}
return res.ToString();
}
}
And some example output:
PasswordGenerator.Generate(12)
"pzY=64#-ChS$"
"BG0OsyLbYnI_"
"l9#5^2&adj_i"
"#++Ws9d$%O%X"
"IWhdIN-#&O^s"
To preempt complaints about the use of Random: The primary source of randomness is still the crypto RNG. Even if you could deterministically preordain the sequence coming out of Random (say it only produced 1) you still wouldn't know the next char that would be picked (though that would limit the range of possibilities).
One simple extension would be to add weighting to the different character sets, which could be as simple as upping the max value and adding fall-through cases to increase weight.
switch (_rand.Next(6))
{
// Prefer letters 2:1
case 0:
case 1:
res.Append(lower[b % lower.Count()]);
break;
case 2:
case 3:
res.Append(upper[b % upper.Count()]);
break;
case 4:
res.Append(number[b % number.Count()]);
break;
case 5:
res.Append(special[b % special.Count()]);
break;
}
For a more humanistic random password generator I once implemented a prompt system using the EFF dice-word list.
I don't like the passwords that Membership.GeneratePassword() creates, as they're too ugly and have too many special characters.
This code generates a 10 digit not-too-ugly password.
string password = Guid.NewGuid().ToString("N").ToLower()
.Replace("1", "").Replace("o", "").Replace("0","")
.Substring(0,10);
Sure, I could use a Regex to do all the replaces but this is more readable and maintainable IMO.
For this sort of password, I tend to use a system that's likely to generate more easily "used" passwords. Short, often made up of pronouncable fragments and a few numbers, and with no intercharacter ambiguity (is that a 0 or an O? A 1 or an I?). Something like
string[] words = { 'bur', 'ler', 'meh', 'ree' };
string word = "";
Random rnd = new Random();
for (i = 0; i < 3; i++)
word += words[rnd.Next(words.length)]
int numbCount = rnd.Next(4);
for (i = 0; i < numbCount; i++)
word += (2 + rnd.Next(7)).ToString();
return word;
(Typed right into the browser, so use only as guidelines. Also, add more words).
I created this method similar to the available in the membership provider. This is usefull if you don't want to add the web reference in some applications.
It works great.
public static string GeneratePassword(int Length, int NonAlphaNumericChars)
{
string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
string allowedNonAlphaNum = "!##$%^&*()_-+=[{]};:<>|./?";
Random rd = new Random();
if (NonAlphaNumericChars > Length || Length <= 0 || NonAlphaNumericChars < 0)
throw new ArgumentOutOfRangeException();
char[] pass = new char[Length];
int[] pos = new int[Length];
int i = 0, j = 0, temp = 0;
bool flag = false;
//Random the position values of the pos array for the string Pass
while (i < Length - 1)
{
j = 0;
flag = false;
temp = rd.Next(0, Length);
for (j = 0; j < Length; j++)
if (temp == pos[j])
{
flag = true;
j = Length;
}
if (!flag)
{
pos[i] = temp;
i++;
}
}
//Random the AlphaNumericChars
for (i = 0; i < Length - NonAlphaNumericChars; i++)
pass[i] = allowedChars[rd.Next(0, allowedChars.Length)];
//Random the NonAlphaNumericChars
for (i = Length - NonAlphaNumericChars; i < Length; i++)
pass[i] = allowedNonAlphaNum[rd.Next(0, allowedNonAlphaNum.Length)];
//Set the sorted array values by the pos array for the rigth posistion
char[] sorted = new char[Length];
for (i = 0; i < Length; i++)
sorted[i] = pass[pos[i]];
string Pass = new String(sorted);
return Pass;
}
I've always been very happy with the password generator built-in to KeePass. Since KeePass is a .Net program, and open source, I decided to dig around the code a bit. I ended up just referncing KeePass.exe, the copy provided in the standard application install, as a reference in my project and writing the code below. You can see how flexible it is thanks to KeePass. You can specify length, which characters to include/not include, etc...
using KeePassLib.Cryptography.PasswordGenerator;
using KeePassLib.Security;
public static string GeneratePassword(int passwordLength, bool lowerCase, bool upperCase, bool digits,
bool punctuation, bool brackets, bool specialAscii, bool excludeLookAlike)
{
var ps = new ProtectedString();
var profile = new PwProfile();
profile.CharSet = new PwCharSet();
profile.CharSet.Clear();
if (lowerCase)
profile.CharSet.AddCharSet('l');
if(upperCase)
profile.CharSet.AddCharSet('u');
if(digits)
profile.CharSet.AddCharSet('d');
if (punctuation)
profile.CharSet.AddCharSet('p');
if (brackets)
profile.CharSet.AddCharSet('b');
if (specialAscii)
profile.CharSet.AddCharSet('s');
profile.ExcludeLookAlike = excludeLookAlike;
profile.Length = (uint)passwordLength;
profile.NoRepeatingCharacters = true;
KeePassLib.Cryptography.PasswordGenerator.PwGenerator.Generate(out ps, profile, null, _pool);
return ps.ReadString();
}
I like to look at generating passwords, just like generating software keys. You should choose from an array of characters that follow a good practice. Take what #Radu094 answered with and modify it to follow good practice. Don't put every single letter in the character array. Some letters are harder to say or understand over the phone.
You should also consider using a checksum on the password that was generated to make sure that it was generated by you. A good way of accomplishing this is to use the LUHN algorithm.
public static string GeneratePassword(int passLength) {
var chars = "abcdefghijklmnopqrstuvwxyz##$&ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
Enumerable.Repeat(chars, passLength)
.Select(s => s[random.Next(s.Length)])
.ToArray());
return result;
}
This package allows you to generate a random password while fluently indicating which characters it should contain (if needed):
https://github.com/prjseal/PasswordGenerator/
Example:
var pwd = new Password().IncludeLowercase().IncludeUppercase().IncludeSpecial();
var password = pwd.Next();
If you want to make use of the cryptographically secure random number generation used by System.Web.Security.Membership.GeneratePassword but also want to restrict the character set to alphanumeric characters, you can filter the result with a regex:
static string GeneratePassword(int characterCount)
{
string password = String.Empty;
while(password.Length < characterCount)
password += Regex.Replace(System.Web.Security.Membership.GeneratePassword(128, 0), "[^a-zA-Z0-9]", string.Empty);
return password.Substring(0, characterCount);
}
check this code...
I added the .remove(length) to improve anaximander's response
public string GeneratePassword(int length)
{
using(RNGCryptoServiceProvider cryptRNG = new RNGCryptoServiceProvider();)
{
byte[] tokenBuffer = new byte[length];
cryptRNG.GetBytes(tokenBuffer);
return Convert.ToBase64String(tokenBuffer).Remove(length);
}
}
How to Generate the Random Password in C#.
Output : (https://prnt.sc/11fac8v)
Run : https://onlinegdb.com/HJe5OHBLu
private static Random random = new Random();
public static void Main()
{
Console.WriteLine("Random password with length of 8 character.");
Console.WriteLine("===========================================");
Console.WriteLine("Capital latters : 2");
Console.WriteLine("Number latters : 2");
Console.WriteLine("Special latters : 2");
Console.WriteLine("Small latters : 2");
Console.WriteLine("===========================================");
Console.Write("The Random Password : ");
Console.WriteLine(RandomStringCap(2) + RandomStringNum(2) + RandomStringSpe(2) + RandomStringSml(2));
Console.WriteLine("===========================================");
}
public static string RandomStringCap(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
public static string RandomStringNum(int length)
{
const string chars = "0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
public static string RandomStringSml(int length)
{
const string chars = "abcdefghijklmnopqrstuvwxyz";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
public static string RandomStringSpe(int length)
{
const string chars = "!##$%^&*_-=+";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
Pretty easy way to require one from each group using Random and linq-to-objects.
Randomize each group
Select random amount from first group
Select remaining random amounts from following groups
 
Random rand = new Random();
int min = 8;
int max = 16;
int totalLen = rand.Next(min, max);
int remainingGroups = 4;
string[] allowedLowerChars = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z".Split(',');
string [] allowedUpperChars = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z".Split(',');
string [] allowedNumbers = "1,2,3,4,5,6,7,8,9,0".Split(',');
string [] allowedSpecialChars = "!,#,#,$,%,&,?".Split(',');
var password = allowedLowerChars.OrderBy(c => rand.Next()).Take(rand.Next(1, totalLen-remainingGroups--)).ToList();
password.AddRange(allowedUpperChars.OrderBy(c => rand.Next()).Take(rand.Next(1, totalLen-password.Count-remainingGroups--)).ToList());
password.AddRange(allowedNumbers.OrderBy(c => rand.Next()).Take(rand.Next(1, totalLen-password.Count-remainingGroups--)).ToList());
password.AddRange(allowedSpecialChars.OrderBy(c => rand.Next()).Take(totalLen-password.Count).ToList());
password = password.OrderBy(c => rand.Next()).ToList(); // randomize groups
Inspired by the answer from #kitsu.eb, but using RandomNumberGenerator instead of Random or RNGCryptoServiceProvider (deprecated in .NET 6), and added a few more special characters.
Optional parameter to exclude characters that will be escaped when using System.Text.Json.JsonSerializer.Serialize - for example & which is escaped as \u0026 - so that you can guarantee the length of the serialized string will match the length of the password.
For .NET Core 3.0 and above.
public static class PasswordGenerator
{
const string lower = "abcdefghijklmnopqrstuvwxyz";
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string number = "1234567890";
const string special = "!##$%^&*()[]{},.:`~_-=+"; // excludes problematic characters like ;'"/\
const string specialJsonSafe = "!##$%^*()[]{},.:~_-="; // excludes problematic characters like ;'"/\ and &`+
const int lowerLength = 26; // lower.Length
const int upperLength = 26; // upper.Length;
const int numberLength = 10; // number.Length;
const int specialLength = 23; // special.Length;
const int specialJsonSafeLength = 20; // specialJsonSafe.Length;
public static string Generate(int length = 96, bool jsonSafeSpecialCharactersOnly = false)
{
Span<char> result = length < 1024 ? stackalloc char[length] : new char[length].AsSpan();
for (int i = 0; i < length; ++i)
{
switch (RandomNumberGenerator.GetInt32(4))
{
case 0:
result[i] = lower[RandomNumberGenerator.GetInt32(0, lowerLength)];
break;
case 1:
result[i] = upper[RandomNumberGenerator.GetInt32(0, upperLength)];
break;
case 2:
result[i] = number[RandomNumberGenerator.GetInt32(0, numberLength)];
break;
case 3:
if (jsonSafeSpecialCharactersOnly)
{
result[i] = specialJsonSafe[RandomNumberGenerator.GetInt32(0, specialJsonSafeLength)];
}
else
{
result[i] = special[RandomNumberGenerator.GetInt32(0, specialLength)];
}
break;
}
}
return result.ToString();
}
}
Since Random is not secure and RNGCryptoServiceProvider is obsolte I ended up doing this:
// possible characters that password can have
private const string passChars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789" +
"!##$%.-_"
;
public static string GetRandomPassword(int length)
{
char[] p = new char[length];
for (int i = 0; i < length; i++)
p[i] = passChars[RandomNumberGenerator.GetInt32(0, passChars.Length)];
return new string(p);
}
Here is a solution that uses RNGCryptoServiceProvider to mimic the functionality of Membership.GeneratePassword from the System.Web.Security namespace.
I needed a drop-in replacement for running it in Azure Function.
It can be tested here:
https://dotnetfiddle.net/V0cNJw
public static string GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
{
const string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
const string nonAlphanumericChars = "!##$%^&*()_-+=[{]};:<>|./?";
var randNum = new byte[4];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(randNum);
var randomSeed = BitConverter.ToInt32(randNum, 0);
var random = new Random(randomSeed);
var chars = new char[length];
var allowedCharCount = allowedChars.Length;
var nonAlphanumericCharCount = nonAlphanumericChars.Length;
var numNonAlphanumericCharsAdded = 0;
for (var i = 0; i < length; i++)
{
if (numNonAlphanumericCharsAdded < numberOfNonAlphanumericCharacters && i < length - 1)
{
chars[i] = nonAlphanumericChars[random.Next(nonAlphanumericCharCount)];
numNonAlphanumericCharsAdded++;
}
else
{
chars[i] = allowedChars[random.Next(allowedCharCount)];
}
}
return new string(chars);
}
}
Here is a version that runs on .Net 6.0+
Sandbox: https://dotnetfiddle.net/XqgTSg
public static string GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
{
const string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
const string nonAlphanumericChars = "!##$%^&*()_-+=[{]};:<>|./?";
var randNum = new byte[4];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randNum);
var randomSeed = BitConverter.ToInt32(randNum, 0);
var random = new Random(randomSeed);
var chars = new char[length];
var allowedCharCount = allowedChars.Length;
var nonAlphanumericCharCount = nonAlphanumericChars.Length;
var numNonAlphanumericCharsAdded = 0;
for (var i = 0; i < length; i++)
{
if (numNonAlphanumericCharsAdded < numberOfNonAlphanumericCharacters && i < length - 1)
{
chars[i] = nonAlphanumericChars[random.Next(nonAlphanumericCharCount)];
numNonAlphanumericCharsAdded++;
}
else
{
chars[i] = allowedChars[random.Next(allowedCharCount)];
}
}
return new string(chars);
}
}
On my website I use this method:
//Symb array
private const string _SymbolsAll = "~`!##$%^&*()_+=-\\|[{]}'\";:/?.>,<";
//Random symb
public string GetSymbol(int Length)
{
Random Rand = new Random(DateTime.Now.Millisecond);
StringBuilder result = new StringBuilder();
for (int i = 0; i < Length; i++)
result.Append(_SymbolsAll[Rand.Next(0, _SymbolsAll.Length)]);
return result.ToString();
}
Edit string _SymbolsAll for your array list.
Added some supplemental code to the accepted answer. It improves upon answers just using Random and allows for some password options. I also liked some of the options from the KeePass answer but did not want to include the executable in my solution.
private string RandomPassword(int length, bool includeCharacters, bool includeNumbers, bool includeUppercase, bool includeNonAlphaNumericCharacters, bool includeLookAlikes)
{
if (length < 8 || length > 128) throw new ArgumentOutOfRangeException("length");
if (!includeCharacters && !includeNumbers && !includeNonAlphaNumericCharacters) throw new ArgumentException("RandomPassword-Key arguments all false, no values would be returned");
string pw = "";
do
{
pw += System.Web.Security.Membership.GeneratePassword(128, 25);
pw = RemoveCharacters(pw, includeCharacters, includeNumbers, includeUppercase, includeNonAlphaNumericCharacters, includeLookAlikes);
} while (pw.Length < length);
return pw.Substring(0, length);
}
private string RemoveCharacters(string passwordString, bool includeCharacters, bool includeNumbers, bool includeUppercase, bool includeNonAlphaNumericCharacters, bool includeLookAlikes)
{
if (!includeCharacters)
{
var remove = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
foreach (string r in remove)
{
passwordString = passwordString.Replace(r, string.Empty);
passwordString = passwordString.Replace(r.ToUpper(), string.Empty);
}
}
if (!includeNumbers)
{
var remove = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
foreach (string r in remove)
passwordString = passwordString.Replace(r, string.Empty);
}
if (!includeUppercase)
passwordString = passwordString.ToLower();
if (!includeNonAlphaNumericCharacters)
{
var remove = new string[] { "!", "#", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", "=", "{", "}", "[", "]", "|", "\\", ":", ";", "<", ">", "/", "?", "." };
foreach (string r in remove)
passwordString = passwordString.Replace(r, string.Empty);
}
if (!includeLookAlikes)
{
var remove = new string[] { "(", ")", "0", "O", "o", "1", "i", "I", "l", "|", "!", ":", ";" };
foreach (string r in remove)
passwordString = passwordString.Replace(r, string.Empty);
}
return passwordString;
}
This was the first link when I searched for generating random passwords and the following is out of scope for the current question but might be important to consider.
Based upon the assumption that System.Web.Security.Membership.GeneratePassword is cryptographically secure with a minimum of 20% of the characters being Non-Alphanumeric.
Not sure if removing characters and appending strings is considered good practice in this case and provides enough entropy.
Might want to consider implementing in some way with SecureString for secure password storage in memory.
validChars can be any construct, but I decided to select based on ascii code ranges removing control chars. In this example, it is a 12 character string.
string validChars = String.Join("", Enumerable.Range(33, (126 - 33)).Where(i => !(new int[] { 34, 38, 39, 44, 60, 62, 96 }).Contains(i)).Select(i => { return (char)i; }));
string.Join("", Enumerable.Range(1, 12).Select(i => { return validChars[(new Random(Guid.NewGuid().GetHashCode())).Next(0, validChars.Length - 1)]; }))
This is short and it works great for me.
public static string GenerateRandomCode(int length)
{
Random rdm = new Random();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < length; i++)
sb.Append(Convert.ToChar(rdm.Next(101,132)));
return sb.ToString();
}
Here Is what i put together quickly.
public string GeneratePassword(int len)
{
string res = "";
Random rnd = new Random();
while (res.Length < len) res += (new Func<Random, string>((r) => {
char c = (char)((r.Next(123) * DateTime.Now.Millisecond % 123));
return (Char.IsLetterOrDigit(c)) ? c.ToString() : "";
}))(rnd);
return res;
}
Generate random password of specified length with
- Special characters
- Number
- Lowecase
- Uppercase
public static string CreatePassword(int length = 12)
{
const string lower = "abcdefghijklmnopqrstuvwxyz";
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string number = "1234567890";
const string special = "!##$%^&*";
var middle = length / 2;
StringBuilder res = new StringBuilder();
Random rnd = new Random();
while (0 < length--)
{
if (middle == length)
{
res.Append(number[rnd.Next(number.Length)]);
}
else if (middle - 1 == length)
{
res.Append(special[rnd.Next(special.Length)]);
}
else
{
if (length % 2 == 0)
{
res.Append(lower[rnd.Next(lower.Length)]);
}
else
{
res.Append(upper[rnd.Next(upper.Length)]);
}
}
}
return res.ToString();
}
I use this code for generate password with balance composition of alphabet, numeric and non_alpha_numeric chars.
public static string GeneratePassword(int Length, int NonAlphaNumericChars)
{
string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
string allowedNonAlphaNum = "!##$%^&*()_-+=[{]};:<>|./?";
string pass = "";
Random rd = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < Length; i++)
{
if (rd.Next(1) > 0 && NonAlphaNumericChars > 0)
{
pass += allowedNonAlphaNum[rd.Next(allowedNonAlphaNum.Length)];
NonAlphaNumericChars--;
}
else
{
pass += allowedChars[rd.Next(allowedChars.Length)];
}
}
return pass;
}
Insert a Timer: timer1, 2 buttons: button1, button2, 1 textBox: textBox1, and a comboBox: comboBox1. Make sure you declare:
int count = 0;
Source Code:
private void button1_Click(object sender, EventArgs e)
{
// This clears the textBox, resets the count, and starts the timer
count = 0;
textBox1.Clear();
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
// This generates the password, and types it in the textBox
count += 1;
string possible = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
string psw = "";
Random rnd = new Random { };
psw += possible[rnd.Next(possible.Length)];
textBox1.Text += psw;
if (count == (comboBox1.SelectedIndex + 1))
{
timer1.Stop();
}
}
private void Form1_Load(object sender, EventArgs e)
{
// This adds password lengths to the comboBox to choose from.
comboBox1.Items.Add("1");
comboBox1.Items.Add("2");
comboBox1.Items.Add("3");
comboBox1.Items.Add("4");
comboBox1.Items.Add("5");
comboBox1.Items.Add("6");
comboBox1.Items.Add("7");
comboBox1.Items.Add("8");
comboBox1.Items.Add("9");
comboBox1.Items.Add("10");
comboBox1.Items.Add("11");
comboBox1.Items.Add("12");
}
private void button2_click(object sender, EventArgs e)
{
// This encrypts the password
tochar = textBox1.Text;
textBox1.Clear();
char[] carray = tochar.ToCharArray();
for (int i = 0; i < carray.Length; i++)
{
int num = Convert.ToInt32(carray[i]) + 10;
string cvrt = Convert.ToChar(num).ToString();
textBox1.Text += cvrt;
}
}

Categories

Resources