[Sql-Server]what data type to use for password salt and hash values and what length? - sql-server-2005

I am generating salt and hash values from my passwords by using,
string salt = CreateSalt(TxtPassword.Text.Length);
string hash = CreatePasswordHash(TxtPassword.Text, salt);
private static string CreateSalt(int size)
{
//Generate a cryptographic random number.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
// Return a Base64 string representation of the random number.
return Convert.ToBase64String(buff);
}
private static string CreatePasswordHash(string pwd, string salt)
{
string saltAndPwd = String.Concat(pwd, salt);
string hashedPwd =
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPwd, "sha1");
return hashedPwd;
}
What datatype you would suggest for storing these values in sql server? Any suggestion...
Salt:9GsPWpFD
Hash:E778AF0DC5F2953A00B35B35D80F6262CDBB8567

ASPNET_DB says this - can't go wrong.
Password nvarchar(128) NOT NULL,
PasswordSalt nvarchar(128) NOT NULL,
while 128 may seem like a lot, various types of encryption can result in larger strings than you started out with. There is absolutely no reason not to follow the lead of the very smart people who have spend thousands of man hours developing the asp.net membership system.

We store our passwords as a binary SHA512 hash

Related

Autosuggestion on encrypted Data(AES-256 GCM Mode)

For PII purposes, we are encrypting the database fields like email etc.
Now for exact match queries we are also keeping a hashed form(HMAC) for the fields.
But how to run the autosuggestion from Solr / like queries from MySQL.
My encryption code is
public String encrypt(byte[] plaintext, byte[] dataKey, String version) throws Exception {
long startTime = System.currentTimeMillis();
// Generate Initialization Vector
byte[] IV = generateIV();
// Get Cipher Instance
Cipher cipher = getCipher();
// Store Version
byte[] versionArr = new byte[3];
versionArr = version.getBytes();
// Generate Key
SecretKeySpec keySpec = new SecretKeySpec(dataKey, "AES");
// Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_SIZE_BYTES * 8, IV);
// Initialize Cipher for ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
// Perform Encryption
byte[] cipherText = cipher.doFinal(plaintext);
int capacity = 3 + GCM_IV_SIZE_BYTES + plaintext.length + GCM_TAG_SIZE_BYTES;
// Create ByteBuffer & add IV & CipherText
ByteBuffer buffer = ByteBuffer.allocate(capacity);
buffer.put(versionArr);
buffer.put(IV);
buffer.put(cipherText);
long endTime = System.currentTimeMillis();
// return the final encrypted cipher txt
return Base64.getEncoder().encodeToString(buffer.array());
}
private static byte[] generateIV() {
final Random r = new SecureRandom();
byte[] IV = new byte[GCM_IV_SIZE_BYTES];
r.nextBytes(IV);
return IV;
}
private static Cipher getCipher() {
try {
return Cipher.getInstance("AES/GCM/NoPadding");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
return null;
}
Short answer, it’s possible, but quite difficult.
Long answer:
One of the basics of hashes is that the hash changes a lot, by changing the input only a little, so there is no way to know if a hash is close to matching the input value.
Now you might think inputting the hash into the search engine might work and with some customization to the tokenizer (the thing that takes the search input and splits it into small parts for the engine to match), this would actually work. However, you did just make it possible to reverse the hash, let me explain:
For autocomplete of a single field, the tokenizer would use an edge n-gram. What this does is splitting a single string into multiple tokens that can be exactly matched, for example john#gmail.com would be split into:
j, jo, joh, john, john#, …, john#gmail.c, john#gmail.co, john#gmail.com
Now the search engine can search for exact matches on all the tokens and recommend the closest matches as possible values.
If you would customize the tokenizer, to hash everything before it is stored, and then hased the input upon search, this would absolutely work, but now lets look at what happens when an attacker gets the hashed tokenized data.
As in the example with john#gmail.com the first stored value would be the hash of j, which by brute force would take a fraction of a second to reverse. Since you now know the first letter, the second letter would go just as fast and so on. Rendering the whole point of using the hash in the first case obsolete.
ps. A secure hashing algorithm with a salt might work, but the tokenization is almost always done by the search engine, so the compute part of the search engine has to be "secure"
Sources:
https://en.wikipedia.org/wiki/N-gram

How can I get the same MD5 hash from both AS3 and VB.NET? Already have code, it doesn't work

I need to generate a hash of a file in VB.NET on a server and send it to an AS3 client for validation against a file on the client. I chose MD5. I am using the builtin VB.NET MD5 hash and the hurlant MD5 hash on AS3. The results are different.
I am looking for a moderately reliable method of verifying the files are the same. Speed is as important as accuracy. I am open to other hashing algorithms which are at least as reliable/secure as MD5.
If there is a solution using what I have that would be great. If there is another way which works, that's OK too.
My VB Code looks like;
Dim baFileData() As Byte = File.ReadAllBytes(HttpContext.Current.Server.MapPath(strFilePath))
Dim strFileHash As String = GetHash(baFileData)
Function GetHash(theInputBytes() As Byte) As String
Using hasher As MD5 = MD5.Create() ' create hash object
' Convert to byte array and get hash
Dim dbytes As Byte() =
hasher.ComputeHash(theInputBytes)
' sb to create string from bytes
Dim sBuilder As New StringBuilder()
' convert byte data to hex string
For n As Integer = 0 To dbytes.Length - 1
sBuilder.Append(dbytes(n).ToString("X2"))
Next n
Return sBuilder.ToString()
End Using
End Function
My AS3 code looks like this;
private function getFileMD5Hash(flLocalFile:File):String
{
var strmInFile:FileStream = new FileStream();
strmInFile.open(flLocalFile, FileMode.READ);
var strFileData:String = strmInFile.readUTFBytes(strmInFile.bytesAvailable);
strmInFile.close();
var hash:IHash = Crypto.getHash("md5");
var baFileData:ByteArray = Hex.toArray(Hex.fromString(strFileData));
var baHash:ByteArray = hash.hash(baFileData);
var strFileHash:String = Hex.fromArray(baHash);
return strFileHash;
}
#Organis basically gave me the tools in his comments to solve the problem. My only reason for posting this as an answer is to show what the resulting code looks like.
If Organis posts an answer I will give it a vote.
The VB code remained the same.
The AS3 code changed to;
private function getFileMD5Hash(flLocalFile:File):String
{
var strmInFile:FileStream = new FileStream();
strmInFile.open(flLocalFile, FileMode.READ);
var baFileData:ByteArray = new ByteArray;
strmInFile.readBytes(baFileData);
strmInFile.close();
var hash:IHash = Crypto.getHash("md5");
var baHash:ByteArray = hash.hash(baFileData);
var strFileHash:String = Hex.fromArray(baHash).toUpperCase();
return strFileHash;
}

Amazon product lookup signature mismatch

This is the response I'm getting: The request signature we calculated does not match the signature you provided.
Here is the code I'm using to generate the signature:
static byte[] HmacSHA256(String data, byte[] key)
{
String algorithm = "HmacSHA256";
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName)
{
byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
When I use Amazon's test settings, I get the correct signature
key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
dateStamp = '20120215'
regionName = 'us-east-1'
serviceName = 'iam'
However, when I put my live settings in, I get the not matching error.
Here is what I'm using to get my signature:
var reqSig = getSignatureKey("[my secret key]", dateStamp, "us-west-2","AWSECommerceService");
This is what I'm submitting (I'm just testing it in a browser, for now):
ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=[my
access key that corresponds with the secret
key]&Operation=ItemLookup&IdType=UPC&ItemId=635753490879&Timestamp=2019-01-24T19:14:55.2644840Z&Signature=32BA07ECE67F3177BF2EA02923E624D612A45FAA144ED0E43BDDC0DF6574EAC3
I'm not sure if it has to do with the region -- us-west-2 in my case -- because there is no place on the request for a region. I'm not sure how Amazon can test my signature against my parameters if I can't specify what region it is and I've used the region to calculate the signature.
What am I missing?
Ok. After spending days going through this, here is what I had to do:
/*
DOCUMENTATION: https://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html#rest_detailedexample
*/
var itemID = "0679722769";
var accessKeyID = "AKIAIOSFODNN7EXAMPLE";
var timeStamp = DateTime.UtcNow.ToString("o");
var req = $"Service=AWSECommerceService&AWSAccessKeyId={accessKeyID}&Operation=ItemLookup&IdType=UPC&ItemId={itemID}&Version=2013-08-01&Timestamp={timeStamp}";
req = req.Replace(":", "%3A").Replace(",", "%2C"); //UrlDecode certain characters
var reqlist = req.Split('&').ToArray(); //we need to sort our key/value pairs
Array.Sort(reqlist);
req = String.Join("&", reqlist); //join everything back
var reqToSign = $#"GET
webservices.amazon.com
/onca/xml
{req}".Replace("\r", ""); //create the request for signing. We need to replace microsofts's crlf with just a lf; Make sure there are no leading spaces after the linefeeds.
var signage = getSignatureKey("1234567890",reqToSign);
req = $"http://webservices.amazon.com/onca/xml?{req}&Signature={signage}"; //create our request with the signature appended.
return req;
}
private static byte[] HmacSHA256(String data, byte[] key)
{
String algorithm = "HmacSHA256";
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
private static string getSignatureKey(string key, string stringToSign)
{
byte[] kSecret = Encoding.UTF8.GetBytes(key.ToCharArray());
byte[] kSigning = HmacSHA256(stringToSign, kSecret);
return WebUtility.UrlEncode(Convert.ToBase64String(kSigning));
}
Contrary to most of the answers found here and elsewhere, this is the only way that works. The entire request has to be hashed, not just particular parameters. I can't speak to other Amazon services, but the Commerce Service has to be done like this.
Quite a few answers referenced this: https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html or this: Amazon API generating a request signature in C# .NET
As I stated in my question, this is most certainly not correct. If you're not passing a region parameter, how can Amazon create the same signature since it doesn't have all the information.
Anyway, this works now.

Golang database for storing auth info

I use golang as application server. I do user-auth and I search storing system.
I have next model:
{
email string // it should be index
passwordhash string // it should be index too
token string
}
I tried to use key-value storage leveldb with 2 databases:
(key = "email", value = "passwordhash") for login user by passowrd
(key = "email", value = "token") for storing user's auth info
But I'm not sure that double email is good idea. Could you recommend me solution for storing auth info for golang?
Using email as a unique identifier is fine; you can just append a relevant string to your key to differentiate the key value, such as
(key = "email", value = "passwordhash") for login user by password
(key = "email:token", value = "token") for storing user's auth info

Using Jasypt: The checkPassword method is returning false when the passwords should match.

To give you some background, my team and I are creating a program that stores usernames and passwords in a database. We are using Java and interacting with the Database through java code.
We use Jasypt to encrypt the usernames and passwords. I am using the BasicPasswordEncryptor in Jasypt to encrypt both. The usernames encrypt fine and are stored in the database fine. However, when the login is checked and said BasicPasswordEncryptor attempts to check the plaintext username against the encrypted password, it always returns false. I have done a series of checks to focus down where the problem is occuring. As far as I know, it's a problem with Jasypt. Does anyone know what the problem is, a possible solution, or a more optimal method? Thank you. I will post the code.
Here is where the encryption occurs.
public void register(String userName, String passWord){
String encryptedUsername = e.encryptPassword(userName);
String encryptedPassword = e.encryptPassword(passWord);
System.out.println("Registered eU: " + encryptedUsername);
try {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/PandaBox", "root", "");
statement = con.prepareStatement("insert into Users (username, password, logged) values (?,?,?)");
statement.setString(1, encryptedUsername);
statement.setString(2, encryptedPassword);
statement.setInt(3, 0);
boolean x = statement.execute();
System.out.println("IT REGISTERED");
} catch (SQLException o) {
o.printStackTrace();
}
}
Where "e" is the BasicPasswordEncryptor object. Here is the login check.
public boolean checkLogin(String inputedUsername, String inputedPassword) {
try {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/PandaBox", "root", "");
statement = con.prepareStatement("select * from Users");
rs = statement.executeQuery();
System.out.println(inputedUsername + " / " + inputedPassword);
while(rs.next()){
String usernameInDatabase = rs.getString("username");
System.out.println(usernameInDatabase);
if (e.checkPassword(inputedUsername, usernameInDatabase)) {
System.out.println("Username correct.");
statement = con.prepareStatement("select password from Users where username = ?");
statement.setString(1, usernameInDatabase);
rs = statement.executeQuery();
String passwordInDatabase = rs.toString();
if(passwordIsCorrect(inputedPassword, passwordInDatabase)){
return true;
}
}
}
return false;
} catch (SQLException o) {
// TODO Auto-generated catch block
o.printStackTrace();
return false;
}
}
I'm jasypt's author.
From your message, it isn't clear to me whether you are observing this issue when matching the user name or the password --you say 'attempts to check the plaintext username against the encrypted password', which makes no sense--. Nevertheless, one of the most common reasons for problems like yours is that your database columns are not big enough for storing your hashed user names and/or passwords.
The size of the hashing result will depend on the algorithm and salt configuration being used, but for a BasicPasswordEncryptor, which uses MD5 and a salt size of 8 bytes, you should expect your hashes to be 16-byte (hash) plus 8 bytes (salt), plus 8 additional bytes because of textual Base64 encoding. A total of 32 bytes.
Also think that many DBMS measure varchar fields in chars and not bytes, so you should do the appropiate conversion depending on the character encoding being used at your table.
I always recommend to check column sizes first because many DBMS's do not raise an error if you try to store a varchar which is too long for a column --they simply truncate it. I don't know MySQL's behaviour, but Oracle does exactly this. And when you try to decrypt it back... it doesn't match.
So checking your column sizes could be a good starting point. And remember jasypt has a users forum at http://forum.jasypt.org
Oh, and by the way-- forgive me if this is just ad-hoc demo code, but just in case: you should make sure you close all your Statement and ResultSet objects in 'finally' blocks before reusing them... so you should use different 'statement' and 'rs' variables in the inner iteration block, and close them each time.
Regards.
Optimisation 1 : Use a WHERE clause.