How to generate unique hexadecimal string up to specify characters long - c#

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

Related

How to parse a binary string to a binary literal in C#

Here is my specific problem. I need to represent an integer (like 1,2,3,..) as a binary literal with exactly 128 bits.
This is my string representing 1 in binary:
string = "000...0001"; // 128 characters. all zeros until the last 1
Intended result:
bx000...0001;
This issue is that 128 bits is larger than normal types like int, double, decimal, etc. Thus, I believe you must use the BigInteger class to hold this binary value??
Another way to frame this: How can I make sure my BigInteger value is 16 bytes big?
BigInteger val = new BigInteger(1); // but must be 16 bytes exactly.
You would have to specify the number of bytes and pad whatever is missing with 0's, then you can use the BitArray to get the bit values. Something like this.
public static string GetBitString(BigInteger val, int bytes)
{
byte[] arrayBytes = new byte[bytes];
var valBytes = val.ToByteArray();
for (var i = 0; i < valBytes.Length; i++)
{
arrayBytes[i] = valBytes[i];
}
var arr = new BitArray(arrayBytes);
return $"bx{string.Join("", arr.Cast<bool>().Reverse().Select(c => c ? "1" : "0"))}";
}
Another options is to just resize the array created to be 16 bytes. Something like this
public static string GetBitString(BigInteger val, int bytes)
{
var valBytes = val.ToByteArray();
Array.Resize(ref valBytes, bytes);
return $"bx{string.Join("", new BitArray(valBytes).Cast<bool>().Reverse().Select(c => c ? "1" : "0"))}";
}
Using the ToBinaryString extension method from this answer modified to skip leading zeros and not force a sign zero, you can just use PadLeft to ensure you have leading zeroes:
public static string ToBinaryString(this BigInteger bigint) {
var bytes = bigint.ToByteArray();
// Create a StringBuilder having appropriate capacity.
var base2 = new StringBuilder(bytes.Length * 8);
// Convert remaining bytes adding leading zeros.
var idx = bytes.Length - 1;
for (; idx > 0 && bytes[idx] == 0; --idx)
;
for (; idx >= 0; --idx)
base2.Append(Convert.ToString(bytes[idx], 2).PadLeft(8, '0'));
return base2.ToString();
}
Then with the prefix and the left padding:
var ans = "bx"+val.ToBinaryString().PadLeft(128, '0');

How could I encode a long number using uppercase letters and numbers to make it shorter to type?

Is there a way I could encode a long number (e.g. 12349874529768521) as lower-case letters AND numbers for the purposes of reducing its length? The idea is that a user might have a long number on a piece of paper.
It seems to me that if there are more symbols available, that the resulting number could be made shorter. So I'm looking for something like hexadecimal but using the larger symbol space of A-Z instead of just A-F.
This would be in C# (if it matters)
Base32 encoding is designed to produce an unambiguous, compact, human-readable (and non-obscene!) representation. From Wikipedia:
Base32 has a number of advantages over Base64:
The resulting character set is all one case, which can often be beneficial when using a case-insensitive filesystem, spoken language, or human memory.
The
result can be used as a file name because it can not possibly contain the '/' symbol, which is the Unix path separator.
The alphabet can be selected to avoid similar-looking pairs of different symbols, so the strings can be accurately transcribed by hand. (For example, the RFC 4648 symbol set omits the digits for one, eight and zero, since they could be confused with the letters 'I', 'B', and 'O'.)
A result excluding padding can be included in a URL without encoding any characters.
Base32 also has advantages over hexadecimal/Base16: Base32
representation takes roughly 20% less space. (1000 bits takes 200
characters, compared to 250 for Base16)
Douglas Crockford's original article on Base32 encoding is also well worth a read.
EDIT: here's a bit of C# that'll do base-N encoding of integers:
class Program {
private const string BINARY = "01";
private const string DECIMAL = "0123456789";
private const string HEX = "0123456789abcdef";
private const string BASE32 = "0123456789abcdefghjkmnpqrstvwxyz";
static string EncodeInt32(string alphabet, int value) {
var sb = new StringBuilder();
while (value > 0) {
sb.Insert(0, alphabet[value % alphabet.Length]);
value = value / alphabet.Length;
}
return sb.ToString();
}
static int DecodeInt32(string alphabet, string value) {
int result = 0;
int b = alphabet.Length;
int pow = 0;
for (var i = value.Length-1; i >= 0; i--) {
result += (int)(Math.Pow(b, pow++)) * alphabet.IndexOf(value[i]);
}
return (result);
}
static void Main(string[] args) {
for (var i = 0; i < 1234567890; i += 1234567) {
Console.WriteLine("{0} {1} {2}", i, EncodeInt32(BASE32, i), DecodeInt32(BASE32, EncodeInt32(BASE32, i)));
}
Console.ReadKey(false);
}
}
Example output showing typical reduction in string length:
1227159598 14j9y1e 1227159598
1228394165 14kfknn 1228394165
1229628732 14mn99w 1229628732
1230863299 14ntyy3 1230863299
1232097866 14q0mja 1232097866
1233332433 14r6a6h 1233332433
1234567000 14sbztr 1234567000
How about a BaseN Method to encode/decode your long into a string with characters you defined on your own
public static class BaseN
{
private const string CharList = "0123456789abcdefghijklmnopqrstuvwxyz";
public static String Encode(long input)
{
if (input < 0) throw new ArgumentOutOfRangeException("input", input, "input cannot be negative");
var result = new System.Collections.Generic.Stack<char>();
while (input != 0)
{
result.Push(CharList[(int)(input % CharList.Length)]);
input /= CharList.Length;
}
return new string(result.ToArray());
}
public static long Decode(string input)
{
long result = 0, pos = 0;
foreach (char c in input.Reverse())
{
result += CharList.IndexOf(c) * (long)Math.Pow(CharList.Length, pos);
pos++;
}
return result;
}
}
Usage:
long number = 12349874529768521;
string result = BaseN.Encode(number);
Sample:
https://dotnetfiddle.net/odwFlk
Here's a similar approach to the others, using a Base-N conversion:
using System;
using System.Text;
namespace ConsoleApp3
{
class Program
{
static void Main()
{
long n = 12349874529768521;
string baseChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz##";
var encoded = AsBaseN(n, baseChars.ToCharArray());
Console.WriteLine(encoded); // Prints "9HXNyK2uh"
long decoded = AsLong(encoded, baseChars.ToCharArray());
Console.WriteLine(decoded); // Prints "12349874529768521"
}
public static string AsBaseN(long value, char[] baseChars)
{
var result = new StringBuilder();
int targetBase = baseChars.Length;
do
{
result.Append(baseChars[value % targetBase]);
value /= targetBase;
}
while (value > 0);
return result.ToString();
}
public static long AsLong(string number, char[] baseChars)
{
long result = 0;
int numberBase = baseChars.Length;
long multiplier = 1;
foreach (char c in number)
{
result += multiplier * Array.IndexOf(baseChars, c);
multiplier *= numberBase;
}
return result;
}
}
}
If you want a different set of allowable characters, just change baseChars as appropriate. For example, if you just want 0-9 and A-Z:
string baseChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
This gives a result of T3OPA1YNLD3 (base 36) instead of 9HXNyK2uh (base 64).
I presume you mean you want to represent the number with fewer characters.
Base 36 will do this (0-9, a-z).
You can use a base 36 encoder.
Base36 is a binary-to-text encoding scheme that represents binary data in an ASCII string format by translating it into a radix-36 representation. The choice of 36 is convenient in that the digits can be represented using the Arabic numerals 0–9 and the Latin letters A–Z1 (the ISO basic Latin alphabet).
Here's an example of one, but any should work: https://github.com/thewindev/csharpbase36
Example Usage
// Encoding
Base36.Encode(10); // returns "A"
Base36.Encode(10000); // returns "7PS"
// Decoding
Base36.Decode("Z"); // returns 35L
Base36.Decode("10"); // returns 36L
Base36.Decode("7PS"); // returns 10000L
By default uppercase letters are used. If you really wanted to lowercase then a simple string.ToLowerInvarient() can change that.
However, uppercase is usually easier to read, which is why it's used by default, so you might want to consider using uppercase rather than lowercase.
You could look to Base64 encoding. It uses 0-9, A-Z, a-z, + and / characters. Or Base36, if you're interested only in 0-9 and A-Z.

How to split a number into individual nos

I have a int number = 1782901998 whose Length is 10 numbers; I need to split them into 10 different strings. I tried the following code, but it does not give back any output; I need to assign the each number to a string.
string number = 7894;
char[] numberChars = number.ToString().ToCharArray();
int[] digits = new int[numberChars.length];
for(int i = 0; i < numberChars.length; i++) {
digits[i] = (int)numberChars[i];
}
This code only returns 57 in digits list.
Because your code fills the array with the ASCII code for the characters of the number variable. You can use LINQ like below:
int[] digits = number.Select(c => Convert.ToInt32(c.ToString())).ToArray();
Or if you want to assign the each number to a string simply:
string[] digits = number.Select(c => c.ToString()).ToArray();

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);
}

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