2-way encryption from int into a short string - c#

I'm building a tiny webapplication in which our customers can update some details about their company. The customers currently don't have a login/password and we don't want to validate their registration, so we want to give them a automaticly generated password/key to login to the website.
Our plan to encrypt their customerId and give that to the customer so that he can enter that key on the webapp to allow us to decrypt the key into his ID.
There are about 10K customers and they don't all have an email, so some will receive a letter with the URL and the code. This means that the customer has to type the code in, so the code can't be more than 8 characters (preferably 6).
Here's an empty template:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int passwordLength = 6;
int customerId = 12345;
string encrypted = Crypter.Encrypt(customerId, "secretKey", passwordLength);
if (customerId == Crypter.Decrypt(encrypted, "secretKey"))
{
Console.WriteLine("It worked! Well done!");
}
}
}
public static class Crypter
{
public static string Encrypt(int input, string key, int passwordLength)
{
string encryptedString = "";
//do encrypt stuffz here
return encryptedString;
}
public static int Decrypt(string encryoted, string key)
{
int decrypted = 0;
//do decrypt stuffz here
return decrypted;
}
}
}
=> Can anyone link me to more information on how to do this?
I'm not looking for a "plz send me teh codez" but if anyone has already made something like this, feel free to share.
Thanks in advance for any information.

Don't base your secret code on user ID. Instead, generate a random 6 character string for each customer and store it in the database. It's not vulnerable to finding the actual algorithm.

Firstly, I'm not sure if your idea is a very good one. However, putting that aside for a moment, I'm not sure you really need to encrypt/decrypt anything.
What you're saying is that you'll take some internal customer ID and turn it into some other ID (in your case, and encrypted version of the internal customer ID). Why not just create 2 keys - an internal customer ID (the one you keep in your database and use as the primary key) and external customer ID.(another 8 digit unique key that is used as an alternative). You store both in your database and when they "login" you lookup based upon the later.
I would as you you this though: What stops someone guessing your 6 or 8 digit keys. Regardless of whether they're encrypted IDs of just some random set of characters, with only 6 or 8 digits it won't take long for someone to run an attack on your site and guess someones key. The very fact that you're going to format these keys into exactly 6 or 8 digits makes the attacker's job easier.
I think you'd be better of sending out this 8 digit key, getting the user to enter some info that you already know (their name, e-mail address, company name etc) and then getting them to define a userid/login of their choice.

Not sure that I quite understand your intentions here. Can't you simply generate a UUID or something akin and use that (or part of it) as the code for a user? You would simply need to store it alongside the user ID in the database.
As an alternative to insure uniqueness, you could generate a N-char code based on two separate inputs. Say, 5 out of 8 chars could could be generated randomly, while the other 3 would be uniquely based on the customer ID.

I agree with another poster who says don't base the encrypted string on something in your database. It is much easier to generate unique random strings to store in the database.
But, if you must use the user ID, I suggest looking at the following namespace.
System.Security.Cryptography

Related

Generate password based on string in C#

I'd like to generate (secure) local admin passwords based on computer names in our organisation. This way I can build a small UI that takes the computername and gives the password.
With PowerShell we will use the same DLL to generate the password and set it on each workstation.
I've already searched, but all the things I find about cryptography in C# is to hash a password, but I need the hash itself to be the password.
The password should also be of a length between 8 and 12 characters to make it easy enough to type it in.
I'm using .NET Core 2.0 (could use .NET Framework too if needed)
You definitely want to be able to change the passwords on your machines, so include some sort of date or counter in the formula.
You ideally also want to include some form of authentication into the tool, whether that be a master password, a complicated thing with smartcards, or something else. That way when your tool gets into the hands of a baddie they don't necessarily get all your data.
If you go the master password route, you need a plan for how to deal with suspecting that got leaked. (Including someone who knew it leaving the organization, since that's a leak.)
A strawman example which includes:
Using a date
Using a master password
Using HMAC to process the machine name, keyed by a key from the master password
An iteration count to PBKDF2 which matches modern computers.
.
private static string GeneratePassword(
string masterPassword,
string machineName,
DateTimeOffset lastChangeDate)
{
// Use the date (ignoring time) of the last password change as a salt.
byte[] salt = BitConverter.GetBytes(lastChangeDate.ToUniversalTime().Date.Ticks);
HashAlgorithmName prf = HashAlgorithmName.SHA256;
using (var pbkdf2 = new Rfc2898DeriveBytes(masterPassword, salt, 123456, prf))
{
byte[] key = pbkdf2.GetBytes(256 / 8);
using (HMAC hmac = new HMACSHA256(key))
{
byte[] value = hmac.ComputeHash(
Encoding.UTF8.GetBytes(machineName.ToUpperInvariant()));
// Or however long.
return Convert.ToBase64String(value).Substring(0, 16);
}
}
}
The Rfc2898DeriveBytes constructor overload which takes a HashAlgorithmName for the PBKDF2-PRF is new in netcoreapp20. If you are trying to be netstandard20 you can drop the last parameter and use the SHA-1-based version with probably little harm (since HMACSHA-1 isn't currently considered broken).
When going to change a password for a machine you'd enter the date of the last generation to get the existing one. Then enter today's date to get the new value, then write down the new date in whatever text file / spreadsheet / database / sticky note remembers these things.
Another alternative is generating random passwords and saving them in an encrypted structured file. Something like EnvelopedCms as the encryption container gives you smartcard for nearly free, and lets you add/remove readers without changing all the machine passwords (adding is easy, removing might warrant changing them all anyways).
Which is to say: Building a stable generator and deploying the usage is easy. It's maintaining it that gets tricky. Maintaining random might be easier, therefore it's possibly better to pay the cost up front.
I don't know if this is such a good idea - the tool only works as long as the passwords on each and every computer stay unchanged.
Anyway, you could hash the computer name and use the result as a password. Most if not all hashes produce larger hashes than 8-12 "easy enough to type in" characters, but you can solve that by:
Base64 encoding the hash (to get letters, numbers and a couple of other characters)
Take the desired number of characters from the result.
To make this a bit safer, let your UI take a password (a single one) and append it to the computer name before computing the hash. This way, when someone steals your tool, they still won't be able to generate valid passwords.
You won't ever be able to change that password, though. If you share it with a coworker, they will know how to reproduce every password, forever.

Identify the recipient(s) KeyId from PGP encrypted data using the BouncyCastle C# library

I have developed a library to perform PGP signing/encryption and decryption/validation of files against one or more recipients. This part works great and works with large files using streams nicely and efficiently.
Part of the PGP Message Exchange Formats specification (RFC 1991) states the following:
...
6.7 User ID Packet
Purpose. A user ID packet identifies a user and is associated with a
public or private key.
Definition. A user ID packet is the concatenation of the following
fields:
(a) packet structure field (2 bytes);
(b) User ID string.
The User ID string may be any string of printable ASCII characters.
However, since the purpose of this packet is to uniquely identify an
individual, the usual practice is for the User ID string to consist of
the user's name followed by an e-mail address for that user, the
latter enclosed in angle brackets.
...
The application I am creating will need to attempt to identify the appropriate key for decrypting the files automatically so that I have as little user intervention as possible. If the key can not be identified (for example, if the recipient(s) are hidden) the application will prompt for the selection of the correct key. I am trying to make it as streamlined as possible.
The RFC suggests the packet is not part of the encrypted data which makes sense. PGP makes it easy to try and identify who encrypted the data. This is evident when you try and decrypt a file using Kleopatra when it has the relevant keys added to its key database. In this instance, it will prompt for the password protecting the secret key.
My specific question is:
How do I use the C# BouncyCastle library to read which recipients the encrypted data was intended to? In otherwords, which private key to use for decryption?
I have tried to find examples using the Bouncy Castle GitHub repository and couldn't see any that demonstrated this particular problem. I also looked at as many google search results for this question to no avail.
I found the answer to my question. I assumed that if it was part of the PGP specification then it must be possible without too much bother. I therefore decided to scrutinise the decryption process and all of the objects used throughout it.
Using the debugger I enumerated the items within the PgpEncryptedDataList and found the key ID for the public key that encrypted it inside the individual PgpPublicKeyEncryptedData object.
The object contains a property of type long called KeyId. This was the value I was looking for to match against the keys stored in the application.
The following snippet is just an example of what I used to reach the KeyId property:
using (var inputFile = File.OpenRead(#"E:\Staging\6114d23c-2595abef\testfile.txt.gpg"))
using (var decoderStream = PgpUtilities.GetDecoderStream(inputFile))
{
var objectFactory = new PgpObjectFactory(decoderStream);
var encryptedList = (PgpEncryptedDataList)objectFactory.NextPgpObject();
foreach (var encryptedData in encryptedList.GetEncryptedDataObjects().Cast<PgpPublicKeyEncryptedData>())
{
var keyId = encryptedData.KeyId.ToString("X");
Console.WriteLine($"Encryption Key ID: {keyId}");
}
}
Setting a breakpoint after the first enumeration you can examine the encryptedData variable and observe something similar to:
So, after all the struggle, it was actually very simple. Accessing the KeyId during the decryption process is then straightforward and you can automagically go and grab the correct private key to do the decryption.
For completeness, it is common for PGP that files are encrypted for more than just one recipient. In this case, you will see more than one encrypted data object. It doesn't mean the data is encrypted twice. Only the session key. The session key is encrypted N number of times where N is the number of recipients. This allows each recipient to be able to decrypt one of the sessions keys and then to go ahead and decrypt the data.
Refer to the image below showing two objects, and as you would expect, two KeyId properties :)
This snippet is from the PgpDecrypt.cs which already looks through the encrypted objects and checks the key identifier against the PgpSecretKeyRingBundle passed in as a parameter:
foreach (PgpPublicKeyEncryptedData pked in encryptedDataList.GetEncryptedDataObjects())
{
privateKey = PgpKeyHelper.FindSecretKey(secretKeyRing, pked.KeyId, passPhrase.ToCharArray());
if (privateKey == null)
{
continue;
}
encryptedData = pked;
break;
}
For anyone wishing to have a head start with PGP, BouncyCastle and C#, please refer to my library which contains a compilation of many PGP functions. The PgpDecrypt class can be changed to automatically incorporate the key discovery as discussed in this question.

How to validate a logged in user against string key (serial key) to carry out some specific actions in asp.net mvc?

I am a complete beginner with asp.net mvc and frankly with coding too. I am creating my first MVC application. I set a the asp.net identity system and it is working just fine. I have some action methods in my controllers where i want the logged in Users to provide a serial key (14 Alpha Numeric Letters) in order to be authorized for carrying some tasks. I've read tons of articles on custom AuthorizeAttribute but instead of making a solution I am making it more difficult as it should be.
These serial keys should be saved somewhere on the application maybe on the back end database. the user that wants to access a specific action method should provide a serial key.
The whole scenario is like licensing a software or antivirus. Any realistic example or a specific tutorial on this will help too much.
Thanks
As asked by OP for example of hashing I will expand on topic. First thought that comes to mind when we are speaking of web security is Hashing.
What is hashing? Hashing is one way data encoding. For example you have a password, how would you secure it? You Hash it and store it in your database. When user tries to login second time you have his password hashed and stored in database. Now he enters a password, you hash it and look if it does match in database.
For your particular case:
You would want to have an access to the storage which would contain hashed serial-key values.
When user inputs some serial-key you hash it using same method (as used to hash serial-key).
Look for match in your storage for value provided by user. If there is a match user has inserted correct serial-key.
Example of hashing with salt:
static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt)
{
HashAlgorithm algorithm = new SHA256Managed();
byte[] plainTextWithSaltBytes =
new byte[plainText.Length + salt.Length];
for (int i = 0; i < plainText.Length; i++)
{
plainTextWithSaltBytes[i] = plainText[i];
}
for (int i = 0; i < salt.Length; i++)
{
plainTextWithSaltBytes[plainText.Length + i] = salt[i];
}
return algorithm.ComputeHash(plainTextWithSaltBytes);
}
For Hashing data from MSDN, SO.
Article about hashing.
.NET hashing class for multiple times.
Unfortunately, there is a lot to software security. You will have to do your research before being somewhat secure when it comes to web applications.
You could save the serial keys as Session variables. This will however mean that a user will have to provide the serial key for each action each time the session times out. Creating a separate database table to save serial keys for a user id that can be checked against the validated user is probably a better bet.

User ID obfuscation

I expect this's been asked before but haven't really found an appropriate answer here and also don't have the time to come up with my own solution...
If we have a user table with int identity primary key then our users have consecutive IDs while they register on the site.
The we have user public profile page on the site URL:
www.somesite.com/user/1234
where 1234 is the actual user ID. There is nothing vulnerable to see user's ID per se, but it does give anyone the ability to check how many users are registered on my site... Manually increasing the number eventually gets me to an invalid profile.
This is the main reason why I wand a reversible ID mapping to a seemingly random number with fixed length:
www.somesite.com/user/6123978458176573
Can you point me to a simple class that does this mapping? It is of course important that this mapping is simply reversible otherwise I'd have to save the mapping along with other user's data.
I want to avoid GUIDs
GUIDs are slower to index search them because they're not consecutive so SQL has to scan the whole index to match a particular GUID instead just a particular calculated index page...
If I'd have ID + GUID then I would always need to fetch original user ID to do any meaningful data manipulation which is again speed degradation...
A mathematical reversible integer permutation seems the fastest solution...
I would 100% go with the "Add a GUID column to the table" approach. It will take seconds to generate one for each current user, and update your insert procedure to generate one for each new user. This is the best solution.
However, if you really dont want to take that approach there are any number of obfuscation techniques you could use.
Simply Base64 encoding the string representation of your number is one (bad) way to do it.
static public string EncodeTo64(string toEncode)
{
byte[] toEncodeAsBytes
= System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
string returnValue
= System.Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
static public string DecodeFrom64(string encodedData)
{
byte[] encodedDataAsBytes
= System.Convert.FromBase64String(encodedData);
string returnValue =
System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
return returnValue;
}
Bad because anyone with half an ounce of technical knowledge (hackers/scriptkiddies tend to have that in abundance) will instantly recognise the result as Base64 and easily reverse-engineer.
Edit: This blogpost Obfuscating IDs in URLs with Rails provides quite a workable example. Converting to C# gives you something like:
static int Prime = 1580030173;
static int PrimeInverse = 59260789;
public static int EncodeId(int input)
{
return (input * Prime) & int.MaxValue;
}
public static int DecodeId(int input)
{
return (input * PrimeInverse) & int.MaxValue;
}
Input --> Output
1234 --> 1989564746
5678 --> 1372124598
5679 --> 804671123
This follow up post by another author explains how to secure this a little bit more with a random XOR, as well as how to calculate Prime and PrimeInverse - ive just used the pre-canned ones from the original blog for demo.
Use UUIDs
Make another column in the user table for, e.g. 64 bit integers, and fill it with a random number (each time a new user registered - generate it and check it's unique). A number looks better than UUID, however a bit more coding required.
Use maths. ;) You could generate pair of numbers X, Y such as X*Y = 1 (mod M). E.g. X=10000000019L, Y=1255114267L, and M=2^30. Then, you will have two simple functions:
.
long encode(long id)
{ return (id * X) & M; }
long decode(long encodedId)
{ return (encodedId * Y) & M; }
It will produce nearly random encoded ids. It's easy, but hackable. If someone would bother to hack it, he will be able to guess your numbers and see encoded values too. However, I am not completely sure which complexity it is, but as I remember it's not very easy to hack.
May I suggest that you use a UUID instead. This could be indexable and generated within a stored procedure when you add a new user to the database. This would mean either adding a new column to the database table or a new table containing UUIDs but with the User ID as related key.
edit
If you really want to avoid GUIDs then why not use the users "username" whilst they access their profile page. After all I imagine that you don't assign a user an ID until they have entered valid information and that data has been saved into the database.

Generate a short code based on a unique string in C#

I'm just about to launch the beta of a new online service. Beta subscribers will be sent a unique "access code" that allows them to register for the service.
Rather than storing a list of access codes, I thought I would just generate a code based on their email, since this itself is unique.
My initial thought was to combine the email with a unique string and then Base64 encode it. However, I was looking for codes that are a bit shorter, say 5 digits long.
If the access code itself needs to be unique, it will be difficult to ensure against collisions. If you can tolerate a case where two users might, by coincidence, share the same access code, it becomes significantly easier.
Taking the base-64 encoding of the e-mail address concatenated with a known string, as proposed, could introduce a security vulnerability. If you used the base64 output of the e-mail address concatenated with a known word, the user could just unencode the access code and derive the algorithm used to generate the code.
One option is to take the SHA-1-HMAC hash (System.Cryptography.HMACSHA1) of the e-mail address with a known secret key. The output of the hash is a 20-byte sequence. You could then truncate the hash deterministically. For instance, in the following, GetCodeForEmail("test#example.org") gives a code of 'PE2WEG' :
// define characters allowed in passcode. set length so divisible into 256
static char[] ValidChars = {'2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H',
'J','K','L','M','N','P','Q',
'R','S','T','U','V','W','X','Y','Z'}; // len=32
const string hashkey = "password"; //key for HMAC function -- change!
const int codelength = 6; // lenth of passcode
string GetCodeForEmail(string address)
{
byte[] hash;
using (HMACSHA1 sha1 = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(hashkey)))
hash = sha1.ComputeHash(UTF8Encoding.UTF8.GetBytes(address));
int startpos = hash[hash.Length -1] % (hash.Length - codelength);
StringBuilder passbuilder = new StringBuilder();
for (int i = startpos; i < startpos + codelength; i++)
passbuilder.Append(ValidChars[hash[i] % ValidChars.Length]);
return passbuilder.ToString();
}
You may create a special hash from their email, which is less than 6 chars, but it wouldn't really make that "unique", there will always be collisions in such a small space. I'd rather go with a longer key, or storing pre-generated codes in a table anyway.
So, it sounds like what you want to do here is to create a hash function specifically for emails as #can poyragzoglu pointed out. A very simple one might look something like this:
(pseudo code)
foreach char c in email:
running total += [large prime] * [unicode value]
then do running total % large 5 digit number
As he pointed out though, this will not be unique unless you had an excellent hash function. You're likely to have collisions. Not sure if that matters.
What seems easier to me, is if you already know the valid emails, just check the user's email against your list of valid ones upon registration? Why bother with a code at all?
If you really want a unique identifier though, the easiest way to do this is probably to just use what's called a GUID. C# natively supports this. You could store this in your Users table. Though, it would be far too long for a user to ever remember/type out, it would almost certainly be unique for each one if that's what you're trying to do.

Categories