I'm porting some code that uses incremental SHA-1 heavily:
SHA1 hasher = HashAlgoFactory.Create<SHA1>();
hasher.Initialize();
DiskIOCallback readCallback = null;
readCallback = delegate(bool successful) {
if (successful)
hasher.TransformBlock(hashBuffer, 0, count, hashBuffer, 0);
offset += count;
if (!successful || offset == endOffset)
{
object hash = null;
if (successful)
{
hasher.TransformFinalBlock(hashBuffer, 0, 0);
hash = hasher.Hash;
}
And am looking for a WinRT/Metro equivalent. I've used hasher.HashData before; is there some relatively simple way to get incremental behaviour out of HashData, or some alternative that implements the same functionality as above (in a WinRT/Metro way)? It's entirely possible I'm missing something obvious...
You should use CryptographicHash class:
var hashProvider = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha1);
var hasher = hashProvider.CreateHash();
You can append multiple increments of data:
hasher.Append(bytesPart.AsBuffer());
Once you're done, you retrieve the hash:
var hash = hasher.GetValueAndReset().ToArray();
Related
I'm trying to Generate a 6 digit code to be used for 2 factor authentication, at a first glance I might do something like this:
Random random = new Random();
var securitycode = random.Next(1000000, 10000000);
However this seems somewhat insecure to me because, there probably is a way to predict the next number if you can figure out the seeds by grabbing alot of security codes.
I'm thinking there is a better way to get a secure code using RNGCryptoServiceProvider but i'm a bit confused on how I can assure that the code generated is 6 digits
private string GenerateSecurityCode(int length)
{
var provider = new RNGCryptoServiceProvider();
var byteArray = new byte[8];
provider.GetBytes(byteArray);
var code = BitConverter.ToUInt32(byteArray, 0);
//how can I assure the code is 6 digits
}
Is this a secure way to generate MFA Codes, if not what would be a good method for Generating numeric codes?
I'm not sure if this is the most secure but I ended up doing this:
private string GenerateSecurityCode()
{
var buffer = new byte[sizeof(UInt64)];
var cryptoRng = new RNGCryptoServiceProvider();
cryptoRng.GetBytes(buffer);
var num = BitConverter.ToUInt64(buffer, 0);
var code = num % 1000000;
return code.ToString("D6");
}
I was trying to write some try catch for Convert.FromBase64String() and I found out that it already has TryFromBase64String() method. But it needs 3 arguments:
public static bool TryFromBase64String(string s, Span<byte> bytes, out int bytesWritten);
So how can I use Span<byte> bytes there?
I only found this in docs, but without proper description. Maybe this is too obvious.
https://learn.microsoft.com/en-us/dotnet/api/system.convert.tryfrombase64string?view=netcore-2.1
Thank to #Damien_The_Unbeliever and THIS article I found out more about Span. So...
Span is used for saving memory and don't call GC so much. It can store arrays or portion of array, but I still can't figure out how to use it in that method.
As written in the linked questions, System.Span<T> is a new C# 7.2 feature (and the Convert.TryFromBase64String is a newer .NET Core feature)
To use System.Span<> you have to install a nuget package:
Install-Package System.Memory
Then to use it:
byte[] buffer = new byte[((b64string.Length * 3) + 3) / 4 -
(b64string.Length > 0 && b64string[b64string.Length - 1] == '=' ?
b64string.Length > 1 && b64string[b64string.Length - 2] == '=' ?
2 : 1 : 0)];
int written;
bool success = Convert.TryFromBase64String(b64string, buffer, out written);
Where b64string is your base-64 string. The over-complicated size for buffer should be the exact length of the buffer based on the length of the b64string.
You could use it like this, making use of all the TryFromBase64String arguments:
public string DecodeUtf8Base64(string input)
{
var bytes = new Span<byte>(new byte[256]); // 256 is arbitrary
if (!Convert.TryFromBase64String(input, bytes, out var bytesWritten))
{
throw new InvalidOperationException("The input is not a valid base64 string");
}
return Encoding.UTF8.GetString(bytes.Slice(0, bytesWritten));
}
Here's another approach, using ArrayPool, if you need the buffer only temporarily:
// Minimum length that is sure to fit all the data.
// We don't need to be 100% accurate here,
// because ArrayPool might return a larger buffer anyway.
var length = ((value.Length * 3) + 3) / 4;
var buffer = ArrayPool<byte>.Shared.Rent(length);
try
{
// (buffer is implicitly cast to Span<byte>)
if (Convert.TryFromBase64String(value, buffer, out var bytesWritten))
{
// do something with it...
return Encoding.UTF8.GetString(buffer, 0, bytesWritten);
}
throw new FormatException("Invalid base-64 sequence.");
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
I used it like this:
string base64String = 'somebase64';
Span<byte> bytesBuffer = stackalloc byte[base64String.Length];
if (!Convert.TryFromBase64String(base64String, bytesBuffer, out int bytesWritten))
{
return false;
}
ReadOnlySpan<byte> actualBytes = bytesBuffer[..bytesWritten];
UPDATE:
more precise way to count bytes
const int bitsEncodedPerChar = 6;
int bytesExpected = (base64String.Length * bitsEncodedPerChar) >> 3; // divide by 8 bits in a byte
see https://en.wikipedia.org/wiki/Base64#Base64_table_from_RFC_4648
I'll get right to the question,
We have this block of C# code
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, passwordSaltBytes, iterationCount))
{
pbkdf2Bytes = pbkdf2.GetBytes(derivedLength + iterationCountBytes.Length);
}
Returns a byte array, first index has a value of 252
We attempt the same thing in PHP:
$key = hash_pbkdf2("SHA1", $password, $password.$salt, $iterationCount, 48);
First index is 102...
The values all match before this specific part.
It's just that hashing function that isn't giving me consistent results.
Any help is appreciated, cheers.
Edit - If it's not obvious, I'm trying to understand why those two values don't match, what encoding/decoding etc. am I misunderstanding or doing incorrectly.
This is the full C# code. As you can see there are some unnecessary loops etc. but the reasons why this wasn't working are 2:
As somebody pointed out, the bytes in PHP do no output raw data by default, and thus the hash (and consequently as such,) its bytes, weren't identical with that of the C# script.
Previously, I thought (as others also pointed out) that I should pass in the $salt as it is without any encoding or transformation. But upon looking closer at the actual C# code... we can see in the 2nd for i loop that they're actually appending saltBytes onto passwordBytes, thus creating something similar to $password.$salt in PHP
Combining the two above issues:
Sending the $password.$salt instead of just one, and then setting the $raw_output option to true, outputs the same hash, the same bytes as C# does.
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
byte[] iterationCountBytes = BitConverter.GetBytes(iterationCount);
int derivedLength = passwordBytes.Length + saltBytes.Length;
byte[] passwordSaltBytes = new byte[derivedLength];
byte[] pbkdf2Bytes;
string encryptedString;
for (int i = 0; i < passwordBytes.Length; i++)
{
passwordSaltBytes[i] = passwordBytes[i];
}
for (int i = 0; i < saltBytes.Length; i++)
{
passwordSaltBytes[passwordBytes.Length + i] = saltBytes[i];
}
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, passwordSaltBytes, iterationCount))
{
pbkdf2Bytes = pbkdf2.GetBytes(derivedLength + iterationCountBytes.Length);
}
Thanks.
I'm currently trying to convert this c# code into ruby, but I'm having difficulty with the hex conversion that is being used
public static string Decrypt(string hexString, string key, string iv)
{
var bytes = Enumerable.Range(0, hexString.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hexString.Substring(x, 2), 16))
.ToArray();
//===== AES provider
var provider = new AesCryptoServiceProvider();
provider.Mode = CipherMode.CBC;
provider.Key = Encoding.UTF8.GetBytes(key);
provider.IV = Encoding.UTF8.GetBytes(iv);
var transform = provider.CreateDecryptor();
using (var ms = new MemoryStream(bytes))
{
using (var cs = new CryptoStream(ms, transform, CryptoStreamMode.Read))
{
using (var sr = new StreamReader(cs))
{
cs.Flush();
var plainText = sr.ReadToEnd();
return plainText;
}
}
Here is a fiddle of the working code: https://dotnetfiddle.net/JI8SID
With these inputs:
var iv = "8E394493F1E54545";
var key = "36D65EA1F6A849AF9964E0BAA98096B3";
var encrypted = "0A1D18A104A568FDE4770E0B816870C6";
I should be getting:
"testing"
My code is below, but I keep getting a key length too short (OpenSSL::Cipher::CipherError). I'm guessing there's something wrong with my hex_to_bin conversion, but it is stumping me.
require 'openssl'
def hex_to_bin(str)
str.scan(/../).map { |x| x.hex.chr }.join
end
def decrypt(data, hex_key, hex_iv)
decipher = OpenSSL::Cipher::AES256.new(:CBC)
decipher.decrypt
decipher.key = hex_to_bin(hex_key)
decipher.iv = hex_to_bin(hex_iv)
(decipher.update(hex_to_bin(data)) + decipher.final)
end
iv = "8E394493F1E54545"
key = "36D65EA1F6A849AF9964E0BAA98096B3"
encrypted = "0A1D18A104A568FDE4770E0B816870C6"
puts decrypt(encrypted, key, iv)
Thank you in advance!
Use a key length of exactly the same length specified, in the case given AES256 make the key exactly 32-bytes in length. Otherwise an implementation can do whatever it wants from null padding, the garbage bytes past the end of the key or throw an error.
In the code there is a hexadecimal key of 32-bytes but then it is converted to a binary key of 16-bytes by the call: hex_to_bin(hex_key).
In a similar manner the 16-byte hex iv is being reduced to 8-bytes by the call: hex_to_bin(hex_iv).
You really need to supply longer hex keys. Just eliminating the conversion calls will result in 128-bits of key material.
Your intuition is correct - the problem is the call to hex_to_bin on key and iv. Here is a working decrypt routine which emits the string 'testing' when plugged into your sample code:
def decrypt(data, hex_key, hex_iv)
decipher = OpenSSL::Cipher::AES256.new(:CBC)
decipher.decrypt
decipher.key = hex_key
decipher.iv = hex_iv
(decipher.update(hex_to_bin(data)) + decipher.final)
end
I need to implement hashing (I am not referring encryption) to make some data fields (passwords or some details that do not require getting back in original format, rather only need to match in db) secure. Can you please suggest me the best practices to implement hashing. I will be using C# and SQL Server and it will be a web site.
OK now you've said you're protecting passwords you have some options.
The .NET framework has some built in algorithms - MD5, SHA1, SHA2. MD5 and SHA1 are considered obsolete and dangerous now, instead stick to SHA256.
For example (taken from my book)
static byte[] GenerateSaltedHash(string password, byte[] salt)
{
byte[] plainText = Encoding.UTF8.GetBytes(password);
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];
}
byte[] hash = algorithm.ComputeHash(plainTextWithSaltBytes);
}
Now the salt is there to stop precomputed lookups of hashes (hashing itself is not enough any more, people have precomputed hashes of dictionary words and more). But how do you get a salt? Well it's any unique value really, usually a random set of bytes.
public byte[] GenerateSalt(int length)
{
salt = new byte[length];
// Strong runtime pseudo-random number generator, on Windows uses CryptAPI
// on Unix /dev/urandom
RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
random.GetNonZeroBytes(salt);
return salt;
}
So you'd call GenerateSalt(32) first to get the salt (32 is just an example, longer if you wish. You will need to store the salt alongside the password - you don't need to worry about protecting it at all.
Finally you'll need a compare function. When you want to check passwords you would take the user input, get the salt for that user, generate the hash for the supplied password and stored salt, and then compare. You would do this using something like
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static bool ConstantCompare(byte[] array1, byte[] array2)
{
const byte Zero = 0;
int maxLength = array1.Length > array2.Length ? array1.Length : array2.Length;
bool wereEqual = array1.Length == array2.Length;
byte[] paddedArray1 = new byte[maxLength];
byte[] paddedArray2 = new byte[maxLength];
for (int i = 0; i < maxLength; i++)
{
paddedArray1[i] = array1.Length > i ? array1[i] : Zero;
paddedArray2[i] = array2.Length > i ? array2[i] : Zero;
}
bool compareResult = true;
for (int i = 0; i < maxLength; i++)
{
compareResult = compareResult & paddedArray1[i] == paddedArray2[i];
}
return compareResult & wereEqual;
}
I should, of course, point out the ASP.NET membership functions do salt and hash, so they should probably be a first point of call. No point in rolling your own if someone else has done the work.
Here is an API using PBKDF2 for key stretching ONTOP of hashing, this is now best practice.
https://sourceforge.net/projects/pwdtknet
I think you misunderstand what hashing is. You don't use a hash to "make data fields secure", because a hash can only be calculated in one direction. Compute and store the hash for your data, store the hash only, and you will be unable to retrieve your data later.
You might need to encrypt the data. That is an entirely different can of worms with it's own set of problems: how do you store and protect the decryption key, what encryption algorithm to use, do you do the encryption at the database level (sql server supports this) or the application level? How do you enforce encrypted transfer, and protect against copy of the data by the end user?