How to calculate SHA512/256 in .Net 6? - c#

How to calculate SHA512/256 or SHA512/224 without using external library?
In .Net 6, SHA512 hash can be calculated(documentation). Here is my example:
public string GetHashStringSHA512(string data)
{
using (SHA512 sha512 = SHA512.Create())
{
byte[] bytes = sha512.ComputeHash(Encoding.UTF8.GetBytes(data));
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}

As noted in the comments, it appears that the .Net library has not implemented SHA512/256 or SHA512/224.
To calculate SHA512/256 or SHA512/224 without using external library, the specification would need to be implemented. There's a document on the Cryptology ePrint Archive that includes some sample code. See also the NIST example. There are a variety of open source solutions as well to use as a starting point for your own code, such as the SHA512 library at wolfSSL that includes both SHA512/256 and SHA512/224.

Related

How to change code that uses Span to use byte array instead

I want to try a code sample for libvlcsharp, found here:
https://code.videolan.org/mfkl/libvlcsharp-samples/-/blob/master/PreviewThumbnailExtractor/Program.cs#L113
I want to try it in a Framework 4.6.1 project, but the sample is targeted at .NET 6. I am having trouble getting one line to compile. The section in question is here:
private static async Task ProcessThumbnailsAsync(string destination, CancellationToken token)
{
var frameNumber = 0;
while (!token.IsCancellationRequested)
{
if (FilesToProcess.TryDequeue(out var file))
{
using (var image = new Image<SixLabors.ImageSharp.PixelFormats.Bgra32>((int)(Pitch / BytePerPixel), (int)Lines))
using (var sourceStream = file.file.CreateViewStream())
{
var mg = image.GetPixelMemoryGroup();
for(int i = 0; i < mg.Count; i++)
{
sourceStream.Read(MemoryMarshal.AsBytes(mg[i].Span));
}
Console.WriteLine($"Writing {frameNumber:0000}.jpg");
var fileName = Path.Combine(destination, $"{frameNumber:0000}.jpg");
using (var outputFile = File.Open(fileName, FileMode.Create))
{
image.Mutate(ctx => ctx.Crop((int)Width, (int)Height));
image.SaveAsJpeg(outputFile);
}
}
file.accessor.Dispose();
file.file.Dispose();
frameNumber++;
}
else
{
await Task.Delay(TimeSpan.FromSeconds(1), token);
}
}
}
The troublesome line is :
sourceStream.Read(MemoryMarshal.AsBytes(mg[i].Span));
In .NET 6 there are two overloads,
Read(Span) Reads all the bytes of this unmanaged memory stream
into the specified span of bytes.
Read(Byte[], Int32, Int32) Reads the specified number of bytes into
the specified array.
but in .NET Framework 4.x there is just one
Read(Byte[], Int32, Int32)
I am having trouble understanding what is going on here, can someone please suggest a way to convert the line from the Read(Span) style to the Read(Byte[], Int32, Int32) style so that it works the same? I don't have experience with C#.
Thanks for any advice.
To understand what's happening, consider the following .NET 4.6.1 code which would achieve the same:
var mg = image.GetPixelMemoryGroup();
for(int i = 0; i < mg.Count; i++)
{
Span<byte> span = MemoryMarshal.AsBytes(mg[i].Span);
byte[] buffer = new byte[span.Length];
sourceStream.Read(buffer, 0, buffer.Length);
buffer.CopyTo(span);
}
This is just for demonstration though as it would allocate lots of byte arrays. You're better off "backporting" what new .NET does by default, s. this answer. Especially since you'll run into this again as the SixLabors libraries were written with .NET Core in mind, AFAIK. It may also not be as performant as what new .NET can do in case memory mapped file streams remove the need for the one copy done by default.
Also note that .NET 4.6.1 is no longer supported, and if you consider upgrading, you may find switching to .NET (Core) easier than pursuing backporting a whole library.

Using Bouncy Castle (FIPS) to encrypt/decrypt a very long stream

First some background, in case I'm taking the wrong approach. I have two requirements:
I want to encrypt the data written and read from AnonymousPipeServerStream and AnonymousPipeClientStream
I must use a FIPS-compliant NIST-accredited cryptographic module.
I'm actually using StreamJsonRpc to read and write the pipes, so I have no control over how many bytes are read and written at once. What I'm looking for is an encrypting/decrypting Stream that I can use to wrap unencrypted streams.
I'm trying to use the FIPS-compliant Bouncy Castle .Net library to do this using AES in CTR mode, which I understand is a reasonable way to encrypt a stream.
I can't work out how to increment the counter when encrypting a long data stream, so I get an exception "counter in CTR mode out of range".
Below is a compilable console app which demonstrates what I have so far. It's strongly based on the sample code in section 3.2.2 of the Bouncy Castle BC-FNA user guide.
The code below works, but if you increase the amount of data written to the stream by changing const int COPIES = 50; to const int COPIES = 60;, it will throw an exception.
My questions:
Is this a reasonable approach?
If so, how can I handle large streams?
The code:
using System;
using System.IO;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Fips;
using Org.BouncyCastle.Utilities.Encoders;
namespace Demo
{
class Program
{
static void Main()
{
const int COPIES = 50;
CryptoServicesRegistrar.SetApprovedOnlyMode(true);
var key = new FipsAes.Key(Hex.Decode("aafd12f659cae63489b479e5076ddec2"));
IBlockCipherService provider = CryptoServicesRegistrar.CreateService(key);
// define IV – note 15 bytes, so max message length 255 * 16 bytes
byte[] iv = Hex.Decode("000102030405060708090a0b0c0d0e");
// define data to be encrypted.
string text = "'Twas brillig, and the slithy toves did gyre and gymble in the wabe.\n";
byte[] toBeEncrypted = Encoding.UTF8.GetBytes(text);
// encrypt the data.
var bOut = new MemoryStream();
var encryptorBldr = provider.CreateEncryptorBuilder(FipsAes.Ctr.WithIV(iv));
var encryptor = encryptorBldr.BuildCipher(bOut);
using (Stream encryptingStream = encryptor.Stream)
{
// Write several copies a byte at a time to prove it works.
writeMultipleCopiesOneByteAtOnce(toBeEncrypted, COPIES, encryptingStream); // Change copies to 60 and it breaks.
}
byte[] cipherText = bOut.ToArray();
// decrypt the resulting cipher text
var decryptorBldr = provider.CreateDecryptorBuilder(FipsAes.Ctr.WithIV(iv));
var decryptor = decryptorBldr.BuildCipher(new MemoryStream(cipherText));
using var decIn = decryptor.Stream;
var bytes = readAllOneByteAtOnce(decIn); // Prove that we can read the decryptor stream a byte at a time.
string result = Encoding.UTF8.GetString(bytes); // Print decrypted text.
Console.WriteLine(result);
}
// Just for test purposes. I wouldn't normally write bytes like this.
static void writeMultipleCopiesOneByteAtOnce(byte[] data, int copies, Stream output)
{
for (int i = 0; i < copies; ++i)
{
foreach (byte b in data)
output.WriteByte(b);
}
}
// Just for test purposes. I wouldn't normally read bytes like this.
static byte[] readAllOneByteAtOnce(Stream stream)
{
using var memStream = new MemoryStream();
while (true)
{
int b = stream.ReadByte();
if (b < 0)
return memStream.ToArray();
memStream.WriteByte((byte)b);
}
}
}
}

Sha512 Hashing with Xamarin

Please consider the following code:
SHA512 shaM = new SHA512Managed();
byte[] data = shaM.ComputeHash(Encoding.UTF8.GetBytes("password"));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
string stringyHash = sBuilder.ToString();
I am using the above method to generate a SHA512 hashed password for an android device using Xamarin. However when I output stringyHash I am given a completely different hash to what I expect when using an online hashing service such as:
http://www.convertstring.com/Hash/SHA512
The difference for hashing the string "password" between the online tool and my Xamarin implementation is as follows:
Xamarin:
cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
Online tool:
B109F3BBBC244EB82441917ED06D618B9008DD09B3BEFD1B5E07394C706A8BB980B1D7785E5976EC049B46DF5F1326AF5A2EA6D103FD07C95385FFAB0CACBC86
I am relatively new to Xamarin and have little experience with hashing as a concept, so if someone can explain why the two are different, and how to adjust my code to make sure I am producing a correct hash, it would be appreciated.
cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
Is the SHA-512 hash of a zero length string:
byte[] data = shaM.ComputeHash(Encoding.UTF8.GetBytes(""));
So there is an issue with whatever you feed into your Xamarin method.

Does ECDiffieHellmanCng in .NET have a key derivation function that implements NIST SP 800-56A, section 5.8.1

I have a task at hand that requires deriving key material using the key derivation function described in NIST SP 800-56A, section 5.8.1. I'm not an expert in Cryptography so please excuse me if the question is naive. Here's what I've done so far:
I have the other party's public key and my private key
Now I try to generate the shared secret using ECDH 1.3.132.1.12 using C# (.NET 4) ECDiffieHellmanCng class like so:
// The GetCngKey method reads the private key from a certificate in my Personal certificate store
CngKey cngPrivateKey = GetCngKey();
ECDiffieHellmanCng ecDiffieHellmanCng = new ECDiffieHellmanCng(cngPrivateKey);
ecDiffieHellmanCng.HashAlgorithm = CngAlgorithm.ECDiffieHellmanP256;
ecDiffieHellmanCng.KeyDerivationFunction = ?? // What do I set here
Finally do this:
ecDiffieHellmanCng.DeriveKeyMaterial(otherPartyPublicKey:);
Where/how do I set the other parameters Algorithm ID, Party U Info, Party V Info?
EDIT
I am open to using other libraries like Bouncy Castle (provided they can be called from .NET)
TL;DR; I haven't found a way to derive the symmetric key using KDF described in NIST SP 800-56A, section 5.8.1 using built-in classes in .NET 4.0 alone
The good news (for me :-)) is that it IS possible in .NET 4.0 using the lovely BouncyCastle library (NuGet: Install-Package BouncyCastle-Ext -Version "1.7.0"). Here's how:
STEP 1: Get other party's public key
Depending on your scenario, this may be read from a certificate or come to you as part of the message containing the encrypted data. Once you have the Base64 encoded public-key, read it into a Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters object like so:
var publicKeyBytes = Convert.FromBase64String(base64PubKeyStr);
ECPublicKeyParameters otherPartyPublicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
STEP 2: Read your private-key
This would most-commonly involve reading the private key from a PFX/P12 certificate. The windows account running the code should have access to the PFX/P12 and additionally, if the certificate is imported into a certificate store, you'll need to grant permissions via the All Tasks -> manage private key menu in certmgr.msc
using (StreamReader reader = new StreamReader(path))
{
var fs = reader.BaseStream;
string password = "<password for the PFX>";
Pkcs12Store store = new Pkcs12Store(fs, passWord.ToCharArray());
foreach (string n in store.Aliases)
{
if (store.IsKeyEntry(n))
{
AsymmetricKeyEntry asymmetricKey = store.GetKey(n);
if (asymmetricKey.Key.IsPrivate)
{
ECPrivateKeyParameters privateKey = asymmetricKey.Key as ECPrivateKeyParameters;
}
}
}
}
STEP 3: Compute the shared secret
IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("ECDH");
aKeyAgree.Init(privateKey);
BigInteger sharedSecret = aKeyAgree.CalculateAgreement(otherPartyPublicKey);
byte[] sharedSecretBytes = sharedSecret.ToByteArray();
STEP 4: Prepare information required to compute symmetric key:
byte[] algorithmId = Encoding.ASCII.GetBytes(("<prependString/Hex>" + "id-aes256-GCM"));
byte[] partyUInfo = Encoding.ASCII.GetBytes("<as-per-agreement>");
byte[] partyVInfo = <as-per-agreement>;
MemoryStream stream = new MemoryStream(algorithmId.Length + partyUInfo.Length + partyVInfo.Length);
var sr = new BinaryWriter(stream);
sr.Write(algorithmId);
sr.Flush();
sr.Write(partyUInfo);
sr.Flush();
sr.Write(partyVInfo);
sr.Flush();
stream.Position = 0;
byte[] keyCalculationInfo = stream.GetBuffer();
STEP 5: Derive the symmetric key
// NOTE: Use the digest/Hash function as per your agreement with the other party
IDigest digest = new Sha256Digest();
byte[] symmetricKey = new byte[digest.GetDigestSize()];
digest.Update((byte)(1 >> 24));
digest.Update((byte)(1 >> 16));
digest.Update((byte)(1 >> 8));
digest.Update((byte)1);
digest.BlockUpdate(sharedSecret, 0, sharedSecret.Length);
digest.BlockUpdate(keyCalculationInfo, 0, keyCalculationInfo.Length);
digest.DoFinal(symmetricKey, 0);
Now you have the symmetric key ready to do the decryption. To perform decryption using AES, BouncyCastle IWrapper can be used. Obtain an IWrapper using Org.BouncyCastle.Security.WrapperUtilities by calling WrapperUtilities.GetWrapper("AES//") e.g. "AES/CBC/PKCS7". This will also depend on the agreement between the two communicating parties.
Initialize the cipher (IWrapper) with symmetric key and initialization vector (IV) and call the Unwrap method to get plain-text bytes. Finally, convert to string literal using the character encoding used (e.g. UTF8/ASCII/Unicode)

Sign data with MD5WithRSA from .Pem/.Pkcs8 keyfile in C#

I've got the following code sample in Java, and I need to re-enact it in C#:
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(pkcs8PrivateKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
Signature sign = Signature.getInstance("MD5withRSA");
sign.initSign(privKey);
sign.update(data);
byte[] signature = sign.sign();
Is it possible with the standard .Net Crypto API, or should I use BouncyCastle?
Thanks,
b.
Another way is to use CNG (Cryptography Next Generation), along with the Security.Cryptography DLL from CodePlex
Then you can write:
byte[] dataToSign = Encoding.UTF8.GetBytes("Data to sign");
using (CngKey signingKey = CngKey.Import(pkcs8PrivateKey, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSACng rsa = new RSACng(signingKey))
{
rsa.SignatureHashAlgorithm = CngAlgorithm.MD5;
return rsa.SignData(dataToSign);
}
Updated thanks to Simon Mourier: with .Net 4.6, you no longer need a separate library
I am running into a very similar problem trying to create a native C# tool for packing Chrome extensions (using SHA1, not MD5, but that's not a big difference). I believe I have tried literally every possible solution for .Net: System.Security.Cryptography, BouncyCastle, OpenSSL.Net and Chilkat RSA.
The best solution is probably Chilkat; their interface is the cleanest and most straightforward, it's well-supported and well-documented, and there are a million examples. For instance, here's some code using their library that does something very close to what you want: http://www.example-code.com/csharp/rsa_signPkcs8.asp. However, it's not free (though $150 is not unreasonable, seeing as I have burned 2 days trying to figure this out, and I make a bit more than $75 a day!).
As a free alternative, JavaScience offers up a number of crypto utilities in source form for multiple languages (including C#/.Net) at http://www.jensign.com/JavaScience/cryptoutils/index.html. The one that's most salient to what you are trying to do is opensslkey (http://www.jensign.com/opensslkey/index.html), which will let you generate a RSACryptoServiceProvider from a .pem file. You can then use that provider to sign your code:
string pemContents = new StreamReader("pkcs8privatekey.pem").ReadToEnd();
var der = opensslkey.DecodePkcs8PrivateKey(pemContents);
RSACryptoServiceProvider rsa = opensslkey.DecodePrivateKeyInfo(der);
signature = rsa.SignData(data, new MD5CryptoServiceProvider());
You can use this code . At the first you should download "BouncyCastle.Crypto.dll" from http://www.bouncycastle.org/csharp/ .
/// <summary>
/// MD5withRSA Signing
/// https://www.vrast.cn
/// keyle_xiao 2017.1.12
/// </summary>
public class MD5withRSASigning
{
public Encoding encoding = Encoding.UTF8;
public string SignerSymbol = "MD5withRSA";
public MD5withRSASigning() { }
public MD5withRSASigning(Encoding e, string s)
{
encoding = e;
SignerSymbol = s;
}
private AsymmetricKeyParameter CreateKEY(bool isPrivate, string key)
{
byte[] keyInfoByte = Convert.FromBase64String(key);
if (isPrivate)
return PrivateKeyFactory.CreateKey(keyInfoByte);
else
return PublicKeyFactory.CreateKey(keyInfoByte);
}
public string Sign(string content, string privatekey)
{
ISigner sig = SignerUtilities.GetSigner(SignerSymbol);
sig.Init(true, CreateKEY(true, privatekey));
var bytes = encoding.GetBytes(content);
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = sig.GenerateSignature();
/* Base 64 encode the sig so its 8-bit clean */
var signedString = Convert.ToBase64String(signature);
return signedString;
}
public bool Verify(string content, string signData, string publickey)
{
ISigner signer = SignerUtilities.GetSigner(SignerSymbol);
signer.Init(false, CreateKEY(false, publickey));
var expectedSig = Convert.FromBase64String(signData);
/* Get the bytes to be signed from the string */
var msgBytes = encoding.GetBytes(content);
/* Calculate the signature and see if it matches */
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
return signer.VerifySignature(expectedSig);
}
}
This SO question answers the PKCS#8 part of your code. The rest of the .NET RSA classes are a bizarre jumble of partially overlapping classes that are very difficult to fathom. It certainly appears that signature support is in either of the RSACryptoServiceProvider and/or RSAPKCS1SignatureFormatter classes.
Disclaimer: I know Java and cryptography, but my knowledge of C# and .NET is very limited. I am writing here only under the influence of my Google-fu skills.
Assuming that you could decode a PKCS#8-encoded RSA private key, then, from what I read on MSDN, the rest of the code should look like this:
byte[] hv = MD5.Create().ComputeHash(data);
RSACryptoServiceProvider rsp = new RSACryptoServiceProvider();
RSAParameters rsp = new RSAParameters();
// here fill rsp fields by decoding pkcs8PrivateKey
rsp.ImportParameters(key);
RSAPKCS1SignatureFormatter rf = new RSAPKCS1SignatureFormatter(rsp);
rf.SetHashAlgorithm("MD5");
byte[] signature = rf.CreateSignature(hv);
The relevant classes are in the System.Security.Cryptography namespace.
As for the PKCS#8 key blob decoding (i.e. filling in the rsp fields), I found this page which describes a command-line utility in C# which can perform that job. The source code is provided and is a single C# file. From what I read in it, that code decodes the PKCS#8 file "manually"; indirectly, this should mean that raw .NET (2.0) does not have facilities for PKCS#8 key file decoding (otherwise the author of that tool would not have went to the trouble of implementing such decoding). For your task at hand, you could scavenge from that source file the parts that you need, skipping anything about PEM and symmetric encryption; your entry point would be the DecodePrivateKeyInfo() function, which apparently expects a DER-encoded unencrypted PKCS#8 file, just like Java's PKCS8EncodedKeySpec.

Categories

Resources