Known message and output - nlp-question-answering

If the user knows the output from multiple digestions with a different message. Is that able to be so that the user can get the secret?
Example: Can the user find the unknown secret by knowing the following data?
Edit: updated to make a bit more sense.
unknown = ??;
(unknown+"A") = "";
SHA512(unknown+"B") = "";
SHA512(unknown+"C") = "";
.. etc ... ( can continue indefinitely )
can the unknown variable be discovered?

No secure hash function allows recovering a valid unknown input faster than brute force, even given a set of known plaintexts and hashes. That includes SHA512.
Also, note that HMAC-SHA512 is not implemented as you're suggesting. A system of SHA512(key+data) is vulnerable to a length extension attack: Given the hash for SHA512(key+"Hi"), an attacker can compute the hash for any string with that prefix, such as SHA512(key+"Hi, I'm a hacker") without knowing the key. The HMAC construction avoids this issue.

Related

Workarounds for aes_gcm_siv 32-byte key requirement?

Using any password that isn't 32 bytes makes the program panic with:
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `32`'
The easy solution seems to be either filling it out with zeros or trimming the password from 0 to 31, but why? I doubt it has any security implications since it won't let you use more than 32 bytes. Is there a workaround other than the aforementioned easy solution to allow users to have longer passwords other than rewriting the crate?
The following is a snippet of my code for context:
use aes_gcm_siv::Aes256GcmSiv;
use aes_gcm_siv::aead::{Aead, NewAead, generic_array::GenericArray};
fn encrypt_file(pass: &str, file: &str) {
println!("{}", pass);
let key = GenericArray::from_slice(pass.as_bytes());
let cipher = Aes256GcmSiv::new(&key);
//...
}
I dislike the given usage examples from https://docs.rs/aes-gcm-siv/0.9.0/aes_gcm_siv/. Using a 32 character long hard-coded key seems pretty deceiving.
Part of your problem is that you're using a password directly as a key. You don't want to do that. AES requires a 128-bit, 192-bit, or 256-bit key, and ideally you want it to be indistinguishable from random, which a password typically is not.
If you have a low-entropy secret, you'll probably want to use something like Argon2id to take that passphrase and a random salt of sufficient length to derive a key. If you have a strong secret with lots of entropy, then you can use something like HKDF to generate a key. If you do either of those things, you can generate a key that's exactly 32 bytes long, and, if you want to, a random nonce for the encryption as well. Since you're using AES-GCM-SIV, you can also use a random nonce and just derive the key this way.

How to create API key and Secure Key?

Usually if I consume third party api's, they all give us two keys and they are:
API Key: kind of random number or GUID
Pin/Secure Key/etc: Kind of password or OTP
Now, assuming that I am a third party and I want my API's to be consumed by retailers,
I would also like to create and give these credentials to API consumers.
I work in .net core. Is there any way to create these and also we have to apply security
or token based security.
I am confused because I have no idea how this can be accomlished.
As I researched a few questions on stack-overflow, they suggest to use this, or this, or some use HMAC security but in HMAC, we have to mandate client also to use HMAC so that same signatures can be matched.
I am in confused state of mind. Can you please suggest some ways by which I can do this in .net core
Generating API Keys can basically be broken down to just generating cryptographically random strings.
The following C# code snippet I had lying around generates a random hex string:
using System.Security.Cryptography;
public static string RandomString()
{
byte[] randomBytes = new Byte[64];
using (RandomNumberGenerator rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(randomBytes);
}
SHA256Cng ShaHashFunction = new SHA256Cng();
byte[] hashedBytes = ShaHashFunction.ComputeHash(randomBytes);
string randomString = string.Empty;
foreach (byte b in hashedBytes)
{
randomString += string.Format("{0:x2}", b);
}
return randomString;
}
You can easily change the length of the resulting key by using a different hash function or you can also switch the hex encoding to Base64 (Convert.ToBase64String(hashedBytes) which would replace the foreach loop) encoding which is more common when using API keys.
Edit 2022
Since when I wrote this answer both my understanding of cryptography and .NET Core itself have evolved.
Therefore nowadays I would recommend something like this
public static string GetSecureRandomString(int byteLength = 64)
{
Span<byte> buffer = byteLength > 4096
? new byte[byteLength]
: stackalloc byte[byteLength];
RandomNumberGenerator.Fill(buffer);
return Convert.ToHexString(buffer);
}
The following changes have been implemented:
using stackalloc if possible to reduce managed allocations and GC (garbage collector) pressure, thus increasing performance.
RNGCryptoServiceProvider has been deprecated and replaced with RandomNumberGenerator.Fill() or RandomNumberGenerator.GetBytes(), which also provide cryptographically sufficiently secure random bytes.
(Oversight on my part) There is actually no need for hashing in this context. The randomly generated bytes are secure as they are, so applying a hash function to them not only limits the output length (in case of SHA-256) but is also superfluous.
.NET 5 and later provide the Convert.ToHexString() method to convert bytes to hex.
I added a parameter to specify the length in bytes for the output string. More bytes = better security against brute-force attacks, but it comes with the drawback of a longer output string which may not be as handy as a shorter one. Tweak this value to fit your needs. The default is set to 512 bits (64 bytes) which is sufficiently secure for most applications.
In this example, I have chosen hex-encoding for the final string, but you may use any information-preserving encoding (hex, base64, base32, ASCII, ...) without compromising security.

Securing Password With Login Name

I have a question regarding using Login Names to protect passwords.
You salt the Login Name with a shared salt and then hash it with BCrypt.
You then take the original plain text Login Name and use it as a key to encrypt the password with AES. The result is then salted with a unique salt and finally hashed with BCrypt.
The user's Display Name is set to their User ID (integer), as opposed to their Login Name, when the account is created. The user can change it later, except it can not match anyone else's Display Name or too closely match a case-insensitive comparison to their Login Name.
My question is, if the database were compromised, would this make it significantly harder to recover the passwords than storing plaintext usernames and uniquely salted and BRcypted passwords?
This procedure appears to be very complicated. Actually you are adding a server side secret to the stored hashes (your procedure to hash passwords). That will indeed increase security, as long as the procedure stays secret. In other words, if the attacker has only read access to the database (SQL-injection) you have an advantage, as soon as he has got privileges on the server and knows the code, there is no advantage at all.
There is a much easier and safer way to get this advantage though. Just calculate a BCrypt hash with a random salt (most implementations will do that anyway), then encrypt this hash-value with a server-side key (AES for example). The key should not be derrived form other parameters, instead use a long and random enough key.
I tried to explain the reasons in my tutorial about safely storing passwords, maybe you want to have a look at it.
Edit:
Well i understand now, that you want to handle the login-name like a second password, and will not store it plaintext, instead you store only a BCrypt hash of it with a global "salt".
Lets assume that you are willing to spend 1 second of CPU time for password hashing. In your scheme you would have to split it to half a second for hashing the login-name and half a second for the password. An attacker has to brute-force the login-name first and the password in a second step.
Login-names are normally very weak passwords. While people are learning that passwords need to be strong, login-names often contain only a name with a number and are short.
You need to find the database record with the hash of the login-name, so you cannot use a random salt, instead you need to use a global "salt". This allows to build a single rainbow table to crack all usernames in one go. Important login-names like "admin" can be precalculated.
To avoid duplicates, you have to uppercase/lowercase the login-name, this reduces the search space even more.
That means you spend half a second for a very weak password (login-name), then half a second for the normal password. Compared to investing 1 second for the normal (hopefully strong) password, you are probably decreasing security, by all means i cannot see any advantage.
The authentication code would look something like this.
public static LoginResult TryLogin(string loginName, string pwd)
{
string loginHash = BCrypt.Net.BCrypt.HashPassword(loginName, SHARED_SALT);
WidgetDataContext dc = new WidgetDataContext();
var record = (from rec in dc.usp_GetUserByLoginName(loginHash)
select rec).SingleOrDefault();
if (record == null)
return new LoginResult(null, "Invalid Login Name/Password");
if (record.FailedLoginCount >= MAX_CONSECUTIVE_LOGIN_FAILURES)
return new LoginResult(null, "You have exceeded your maximum number of Login failures. Your account is locked.");
if (record.Locked) // In case account is locked for another reason
return new LoginResult(null, "Your Account is locked.");
pwd = EncryptionServices.Encrypt(pwd, loginName);
pwd = BCrypt.Net.BCrypt.HashPassword(pwd, record.Salt);
if (pwd == record.Password)
{
record.FailedLoginCount = 0;
dc.SubmitChanges();
return new LoginResult(record.UserId, "Login Successful");
}
record.FailedLoginCount++;
dc.SubmitChanges();
return new LoginResult(null, "Invalid Login Name/Password");
}

using counter instead of salt for hashing

I'm developing own protocol for secure message exchanging.
Each message contains the following fields: HMAC, time, salt, and message itself. HMAC is computed over all other fields using known secret key.
Protocol should protect against reply attack. On large time interval "time" record protects against replay attack (both sides should have synchronized clocks). But for protection against replay attack on short time intervals (clocks are not too accurate) I'm planning replace "salt" field with counter increasing every time, when new message is send. Receiving party will throw away messages with counter value less or equal to the previous message counter.
What I'm doing wrong?
Initial counter value can be different (I can use party identifier as initial value), but it will be known to the attacker (party identifier transmitted in unencrypted form).
(https://security.stackexchange.com/questions/8246/what-is-a-good-enough-salt-for-a-saltedhash)
But attacker can precompute rainbow tables for counter+1, counter+2, counter+3... if I will not use really random salt?
I'm not certain of your design and requirements, so some of this may be off base; hopefully some of it is also useful.
First, I'm having a little trouble understanding the attack; I'm probably just missing something. Alice sends a message to Bob that includes a counter, a payload, and an HMAC of (counter||payload). Eve intercepts and replays the message. Bob has seen that one, so he throws it away. Eve tries to compute a new message with counter+1, but she is unable to compute the HMAC for this message (since the counter is different), so Bob throws it away. As long as there is a secret available, Eve should never be able to forge a message, and replaying a message does nothing.
So what is the "known secret key?" Is this key known to the attacker? (And if it is, then he can trivially forge messages, so the HMAC isn't helpful.) Since you note that you have DH, are you using that to negotiate a key?
Assuming I'm missing the attack, thinking through the rest of your question: If you have a shared secret, why not use that to encrypt the message, or at least the time+counter? By encrypting the time and counter together, a rainbow table should be impractical.
If there is some shared secret, but you don't have the processor available to encrypt, you could still do something like MD5(secret+counter) to prevent an attacker guessing ahead (you must already have MD5 available for your HMAC-MD5).
I have attacked this problem before with no shared secret and no DH. In that case, the embedded device needed a per-device public/private keypair (ideally installed during manufacturing, but it can be computed during first power-on and stored in nonvolatile memory; randomness is hard, one option is to let the server provide a random number service; if you have any piece of unique non-public information on the chip, like a serial number, that can be used to seed your key, too. Worst case, you can use your MAC plus the time plus as much entropy as you can scrounge from the network.)
With a public/private key in place, rather than using HMAC, the device just signs its messages, sending its public key to the server in its first message. The public key becomes the identifier of the device. The nice thing about this approach is that there is no negotiation phase. The device can just start talking, and if the server has never heard of this public key, it creates a new record.
There's a small denial-of-service problem here, because attackers could fill your database with junk. The best solution to that is to generate the keys during manufacturing, and immediately insert the public keys into your database. That's impractical for some contract manufacturers. So you can resort to including a shared secret that the device can use to authenticate itself to the server the first time. That's weak, but probably sufficient for the vast majority of cases.

Password security

Currently I am using a particular scheme for securing passwords, and I think I have some points for improvement. The implementation is in Java, so I prefer to use SHA-2 512 as encryption form.
Currently I have a client-server model, so these things can happen:
Client wants to login, he sends his password with one time normal SHA-2 512 encryption over the network.
The server has the passwords stored in the database as for example SHA-2_512(SHA-2_512(password) + salt), with the inner SHA-2_512(password) being the 'encrypted' password it receives over the network.
Password checks are done server side and there is no way anything can leak out from the server, the only possible vulnerability would be if someone could read out the RAM I think.
I have these questions:
An attacker usually creates collision attacks when wanting to hack a password. However how are collision attacks sufficient? If the password needs to be used for other applications like Outlook.com, Facebook or whatever (which likely use another salt as they have nothing to do with my applications), how is a collision attack enough then? Don't you need the real password?
Does SHA-2 512 already use iteration? And even if so, should I change my encryption methods to automatically use a number of iterations plus how many iterations is preferred? I have also read about using a random number of iterations (in a range), how do I store the random factor determenistically?
Should I store system secrets for every iteration in the server code? See http://blog.mozilla.org/webappsec/2011/05/10/sha-512-w-per-user-salts-is-not-enough/ . I could store an array which would hold a static secret for every iteration, with the nth secret being for the nth iteration. Nobody can know the secrets, they are computed once (I guess as encrypting some random string), and then basically stored in the Server's RAM.
Currently I send the typed password from the client to the server as just SHA-2_512(password), should this process be improved, and if so, how? I cannot use salts, because the client does not have the salt available.
Regards.
TLDR: You need to send the password using an encrypted channel, such as TLS. Consider using bcrypt for password hashing.
SHA-2 512 is not an encryption algortihm, it is a message digest algorithm. An encryption algorithm requires a key and a message to encrypt. It produces ciphertext. The important thing is that an encryption algorithm has a decryption algorithm.
ciphertext = E(key, plaintext);
plaintext = D(key, ciphertext);
A message digest takes a piece of plaintext and produces a message digest. There is no corresponding reverse mechanism to take a message digest and retrieve the original message. There is also no secret key.
digest = hash(plaintext);
If an attacker is able to access a database with hashes, the attacker can retrieve the original password by brute forcing, trying lots of guesses with the hash algorithm.
digest1 = hash(guess1);
digest2 = hash(guess2); //repeat with lots of guesses
Firstly, sending a hash over a network is not secure. It needs to be sent through some secure communications mechanism such as SSL. If an attacker can intercept the hash over the communications they may be able to work out the orignal password.
A hash collision is not the same as brute forcing the password. A hash collision is caused when two different messages produce the same message digest.
digest1 = hash(plaintext1);
digest2 = hash(plaintext2);
if ( ( plaintext1 != plaintext2 ) && ( digest1 == digest2 ) )
// hash collision
SHA-512 does not have iterations designed to prevent brute-forcing. The SHA set of algorithms are designed to be efficient. The reason for adding iterations when hashing passwords is to increase the time it takes to brute force a password. The idea being the cost to perform a legitimate login attempt and perform 100 iterations is tiny compared to an attacker who has millions of passwords, each of which requires 100 iterations. Adding more iterations helps reduce the impact of improved processor speeds (which would help an attacker try more iterations quicker).
You should make the number of iterations a configurable limit that is stored against each user. So you store the password hash, salt and iteration count for each user. This means that in the future you can increase the number of iterations to take into account increased hardware power.
Sending the SHA-2 512 in plaintext is not secure. You should send it within an encrypted channel, such as SSL.
Having said all that, SHA-2 is not designed to be a password hashing algorithm. It is designed for message validation and is to be efficient. Consider using a purpose built password hashing algorithm. One example is bcrypt. It is designed to be computationally difficult and has salt and iterations built in.

Resources