I need to generate a HMAC-SHA256 hash in a PCL (developing for Xamarin Forms) which doesn't support the .NET built-in HMAC/cryptography classes, so I'm working with BouncyCastle to implement my cryptography classes.
I need to generate a HMAC-SHA256 hash, but I haven't been able to find any example on Google, nor does BouncyCastle seem to have any documentation for this. Can anyone help me out?
Thanks to the solution here I came up with this code:
public class HmacSha256
{
public byte[] Hash(string text, string key)
{
var hmac = new HMac(new Sha256Digest());
hmac.Init(new KeyParameter(Encoding.UTF8.GetBytes(key)));
byte[] result = new byte[hmac.GetMacSize()];
byte[] bytes = Encoding.UTF8.GetBytes(text);
hmac.BlockUpdate(bytes, 0, bytes.Length);
hmac.DoFinal(result, 0);
return result;
}
}
Corresponding unit test (uses FluentAssertions):
[TestClass]
public class HmacSha256Tests
{
private readonly HmacSha256 _hmac = new HmacSha256();
[TestMethod]
public void Hash_GeneratesValidHash_ForInput()
{
// Arrange
string input = "hello";
string key = "test";
string expected = "F151EA24BDA91A18E89B8BB5793EF324B2A02133CCE15A28A719ACBD2E58A986";
// Act
byte[] output = _hmac.Hash(input, key);
string outputHex = BitConverter.ToString(output).Replace("-", "").ToUpper();
// Assert
expected.Should().Be(outputHex);
}
}
Using this PCL offshoot of BouncyCastle https://www.nuget.org/packages/BouncyCastle-PCL/1.0.0.6 it's really easy, in fact identical to the windows api.
public string ComputeHMAC(string message)
{
var keyBytes = Encoding.UTF8.GetBytes(Constants.API_KEY);
var messageBytes = Encoding.UTF8.GetBytes(message);
var hmac = new HMACSHA256(keyBytes);
byte[] result = hmac.ComputeHash(messageBytes);
return Convert.ToBase64String(result);
}
And a unit test using the actual .Net version:
[Test, AutoMoqData]
public void Hash_Algorithm_Correct (
[NoAutoProperties] HashMacService sut,
string message)
{
string expected;
var key = Encoding.UTF8.GetBytes(Constants.API_KEY);
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
expected = Convert.ToBase64String(hash);
}
var result = sut.ComputeHMAC(message);
Assert.That(result, Is.EqualTo(expected));
}
I was using PCLCrypto but it kept crashing on Xamarin iOS, this was much cleaner and could be unit tested, wheras PCLCrypto required the platform apis so had to be deployed to a device.
private static void CreateToken(string message, string key)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[]keyByte = encoding.GetBytes(key);
HMACSHA256 hmacsha = new HMACSHA256(keyByte);
byte[]messageBytes = encoding.GetBytes(message);
byte[]hashmessage = hmacsha.ComputeHash(messageBytes);
Console.WriteLine(ByteToString(hashmessage));
}
public static string ByteToString(byte[]buff) {
string sbinary = "";
for (int i = 0; i < buff.Length; i++) {
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
Above code saved my time while working for HMAC-SHA256, I hope this may help someone and here is the reference in detail http://billatnapier.com/security01.aspx
Related
One of my web services is about to start receiving responses from another API where the entire body of the response will be encrypted. Having never handled any type of encryption before, I am a bit lost in the weeds. I have a fully fleshed-out example of how to do the decryption, but it is in Java, using Java-native cryptography classes. Can some one please help me translate this to something that will run in .NET, either using BouncyCastle or the native AesGcm class?
Java Example
private static final String ALGORITHM_NAME = "PBKDF2WithHmacSHA512";
private static final String ALGORITHM_STANDARD = "AES";
private static final String CIPHER_TRANSFORMATION = "AES/GCM/NoPadding";
private static final int ITERATION_COUNT = 10000;
private static final int KEY_LENGTH = 256;
private static final GCM_IV_LENGTH = 16;
private static final GCM_TAG_LENGTH = 128;
byte[] apiKeyBytes = Base64.getDecoder().decode(apiKey);
String finalKey = new String(apiKeyBytes, StandardCharsets.UTF_8);
PBEKeySpec spec = new PBEKeySpec(finalKey.toCharArray(), accessId.getBytes(), ITERATION_COUNT, KEY_LENGTH);
SecretKey key = SecretKeyFactory.getInstance(ALGORITHM_NAME).generateSecret(spec);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getEncoded(), ALGORITHM_STANDARD);
public String decryptContent(String content) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, DecoderException,
InvalidKeySpecException, InvalidAlgorithmParameterException {
byte[] decodedContent = Hex.decodeHex(content);
ByteBuffer byteBuffer = ByteBuffer.wrap(decodedContent)
byte[] ivArray = new byte[GCM_IV_LENGTH];
byteBuffer.get(ivArray);
byte[] encrypted = new byte[byteBuffer.remaining()];
byteBuffer.get(encrypted);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, ivArray);
Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
byte[] decryptedOutput = cipher.doFinal(encrypted);
return new String(decryptedOutput, StandardCharsets.UTF_8);
}
I wish that I could even ask better questions for where I need help, but I'm so confused by the vast differences between the Java method and what I have so far in C#. Java for example, doesn't even mention a "nonce."
My current progress in C#
string secret = Encoding.UTF8.GetString(Convert.FromBase64String(APIKEY));
var keyGen = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(secret), Encoding.UTF8.GetBytes(ACCESSID), 10000);
AesGcm _aes = new AesGcm(keyGen.GetBytes(256));
var decodedContent = Hex.Decode(cipher).AsSpan<byte>();
var nonce = decodedContent.Slice(0, 16);
var cipherText = decodedContent.Slice(16, 128);
_aes.Decrypt(nonce, cipherText, **TAG?**, **output byte array**);
What am I missing?
so I am building a message encryption application in C# and Obj-c using Visual Studio Mac and Xcode, I have a text field where the user types their password to decrypt the message. However, after trying several things, I an unable to print the NSTextField as a string to compare it to the password string which is imprinted into the text file.
I have already tried NSString * = [DateCreated stringValue];This did not work.
Code put into Visual Studio by Xcode after designing GUI in ViewController.Designer.cs:
[Outlet]
public static AppKit.NSTextField DateCreated { get; set; }
Code for message decryption where attempting to compare password strings for decryption of message, encryption is working perfectly.
public static string Decrypted(string encrypted)
{
DateTime creation = File.GetCreationTime(#"/Users/bopc/encryptedmessagehere.txt");
string asString = creation.ToString("MM/dd/yyyy hh:mm:ss tt");
var created = ViewController.verify;
if (created != asString)
{
var alert = new NSAlert()
{
AlertStyle = NSAlertStyle.Critical,
InformativeText = "That is incorrect, access is denied",
MessageText = "That is incorrect, access is denied",
};
alert.RunModal();
}
else if (ViewController.dtime == asString)
// This is where I am attempting to input the NSTextField, attempting to convert it to string called dtime.
{
byte[] textbytes = Convert.FromBase64String(encrypted);
AesCryptoServiceProvider endec = new AesCryptoServiceProvider();
endec.BlockSize = 128;
endec.KeySize = 256;
endec.IV = ASCIIEncoding.ASCII.GetBytes(IV);
endec.Key = ASCIIEncoding.ASCII.GetBytes(Key);
endec.Padding = PaddingMode.PKCS7;
endec.Mode = CipherMode.CBC;
ICryptoTransform icrypt = endec.CreateDecryptor(endec.Key, endec.IV);
byte[] enc = icrypt.TransformFinalBlock(textbytes, 0, textbytes.Length);
icrypt.Dispose();
if (ViewController.verify == created)
{
return System.Text.ASCIIEncoding.ASCII.GetString(enc);
}
else if (ViewController.verify != created)
{
var alert = new NSAlert()
{
AlertStyle = NSAlertStyle.Critical,
InformativeText = "It looks like you are trying to fool me by using a key file that was not created for this message. Nice Try.",
MessageText = "It looks like you are trying to fool me by using a key file that was not created for this message. Nice Try.",
};
alert.RunModal();
}
}
return encrypted;
}
Any thoughts are appreciated, than you.
I have a public static method in Invoice.cs class:
public static string CalculateHash(Stream image)
{
using (var sha = SHA256.Create())
{
image.Seek(0, SeekOrigin.Begin);
var hash = sha.ComputeHash(image);
var hashStr = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
return hashStr;
}
}
I have two controllers: HookController.cs and DataController.cs. I try to check if same hash was created for same image, But, hashes which are created by these controllers are not same for same image.
I solved this way.I copied to a new memory stream.
Getting the same Hash value using the below code. Tested it on .Net Framework 4.6.1 console app.
class Program
{
static void Main(string[] args)
{
var fileStream = new FileStream(#"D:\Mukesh\Mukesh.jpg", FileMode.Open);
var result = CalculateHash(fileStream);
Console.ReadKey();
}
public static string CalculateHash(Stream image)
{
using (var sha = SHA256.Create())
{
image.Seek(0, SeekOrigin.Begin);
var hash = sha.ComputeHash(image);
var hashStr = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
return hashStr;
}
}
I'm trying to serialise and encrypt simple dto's as a means to securely hand them around as strings.
It seems that most people point me at Encrypt and decrypt a string when asking about this.
#jbtule took the time to provide a really detailed answer with 2 possible solutions.
I have taken a copy of the second example from his gist https://gist.github.com/jbtule/4336842#file-aesthenhmac-cs (the file named "AESThenHMAC.cs" and put that in to my project.
I then thought it might be good practice to wrap up and quickly test this solution but I can't seem to get it working.
Could someone explain what I am doing wrong here?
Here's my wrapper round #jbtule's code:
using Newtonsoft.Json;
using System.Text;
namespace Core.Data
{
public class AesCrypto<T> : ICrypto<T>
{
public string Encrypt(T source, string salt)
{
var enc = Encoding.Unicode;
var rawData = JsonConvert.SerializeObject(source);
return enc.GetString(AESThenHMAC.SimpleEncryptWithPassword(enc.GetBytes(rawData), salt));
}
public T Decrypt(string source, string salt)
{
var enc = Encoding.Unicode;
var decryptedBytes = AESThenHMAC.SimpleDecryptWithPassword(enc.GetBytes(source), salt);
return JsonConvert.DeserializeObject<T>(enc.GetString(decryptedBytes));
}
}
}
And then a simple unit test to confirm this all works:
public void TestAesCrypto()
{
var testInput = new EncryptableObject { Id = 123, Name = "Victim", When = DateTimeOffset.UtcNow };
var crypto = new AesCrypto<EncryptableObject>();
var saltBytes = new byte[32];
new Random().NextBytes(saltBytes);
var testSalt = Encoding.Unicode.GetString(saltBytes);
var magicString = crypto.Encrypt(testInput, testSalt);
var testOutput = crypto.Decrypt(magicString, testSalt);
Assert.AreEqual(testInput.Id, testOutput.Id);
Assert.AreEqual(testInput.Name, testOutput.Name);
Assert.AreEqual(testInput.When, testOutput.When);
}
For some reason the decryption method returns null because the check performed on line 261 of jbtule's gist compares the value 255 to 0.
This is a follow on from my attempts to talk to the .NET types directly (see AesEncryption doesn't appear to decrypt right?), I just need a solution that consistently works at this point.
There we go, thanks to #dbc ... how I didn't spot that I don't know!
using Newtonsoft.Json;
using System;
using System.Text;
namespace Core.Data
{
public class AesCrypto<T> : ICrypto<T>
{
public string Encrypt(T source, string salt)
{
var e = Encoding.UTF8;
var rawData = e.GetBytes(JsonConvert.SerializeObject(source));
var cipherData = AESThenHMAC.SimpleEncryptWithPassword(rawData, salt);
return Convert.ToBase64String(cipherData);
}
public T Decrypt(string source, string salt)
{
var e = Encoding.UTF8;
var decryptedBytes = AESThenHMAC.SimpleDecryptWithPassword(Convert.FromBase64String(source), salt);
return JsonConvert.DeserializeObject<T>(e.GetString(decryptedBytes));
}
}
}
I've been working over the last few days on trying to port the simple encryption (found here) used to log into the Wizards of the Coast Character Builder API (so my app can download a user's characters directly from the servers) to something I can use in a Windows 8 Metro app, since AesManaged didn't make it into the Metro cryptography libraries. Seeing as I'm a novice programmer at best, this has proven a bit beyond my skills.
Here's the code I need to port over:
public static byte[] SimpleEncrypt(string value, string key)
{
byte[] buffer2;
ICryptoTransform transform = GetSimpleAlgorithm(key).CreateEncryptor();
using (MemoryStream stream = new MemoryStream())
{
using (CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
byte[] bytes = Encoding.UTF8.GetBytes(value);
stream2.Write(bytes, 0, bytes.Length);
stream2.Flush();
stream2.FlushFinalBlock();
stream.Position = 0L;
buffer2 = stream.ToArray();
}
}
return buffer2;
}
private static SymmetricAlgorithm GetSimpleAlgorithm(string key)
{
AesManaged aes = new AesManaged();
byte[] source = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(key));
return new AesManaged { Key = source, IV = source.Take<byte>((aes.BlockSize / 8)).ToArray<byte>() };
}
This is used to encrypt the password prior to passing the login:
contentClient.Login(username, SimpleEncrypt(password, username));
And in case it's needed, the web service is located at: http://ioun.wizards.com/ContentVault.svc
In the comments on that link way up there in the first link, someone suggested some code for Windows 8 back in February, but said code had a few problems I had to fix before it would even compile, and even then, when I try to log in with it, I get an exception back from the service saying "padding is invalid and cannot be removed".
Here's what I'm currently working with:
private static byte[] SimpleEncrypt(string value, string key)
{
var simpleAlgorithm = GetSimpleAlgorithm(key);
var encryptedBuffer = CryptographicEngine.Encrypt(simpleAlgorithm.Item1, CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8), simpleAlgorithm.Item2);
var result = new byte[encryptedBuffer.Length];
CryptographicBuffer.CopyToByteArray(encryptedBuffer, out result);
return result;
}
private static Tuple<CryptographicKey, IBuffer> GetSimpleAlgorithm(string key)
{
var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
var keyAsBinary = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);
var source = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256).HashData(keyAsBinary);
var shortKey = CryptographicBuffer.CreateFromByteArray(UTF8Encoding.UTF8.GetBytes(key).Take((int)provider.BlockLength).ToArray());
return new Tuple<CryptographicKey,IBuffer>(provider.CreateSymmetricKey(source), shortKey);
}
Any help getting this working would be EXTREMELY appreciated.
Welp, spent more time looking it over, and figured out the problem.
The suggested updated version was using the "key" string to create the IV, whereas it should have been using the hash of the key, instead.
Here's the functional version, in case anyone wants it:
private static byte[] SimpleEncrypt(string value, string key)
{
var simpleAlgorithm = GetSimpleAlgorithm(key);
CryptographicKey encryptKey = simpleAlgorithm.Item1;
IBuffer IV = simpleAlgorithm.Item2;
var encryptedBuffer = CryptographicEngine.Encrypt(encryptKey, CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8), IV);
var result = new byte[encryptedBuffer.Length];
CryptographicBuffer.CopyToByteArray(encryptedBuffer, out result);
return result;
}
private static Tuple<CryptographicKey, IBuffer> GetSimpleAlgorithm(string key)
{
var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
var keyAsBinary = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);
var source = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256).HashData(keyAsBinary);
byte[] sourceArray = new byte[source.Length];
CryptographicBuffer.CopyToByteArray(source, out sourceArray);
var shortKey = CryptographicBuffer.CreateFromByteArray(sourceArray.Take((int)provider.BlockLength).ToArray());
return new Tuple<CryptographicKey,IBuffer>(provider.CreateSymmetricKey(source), shortKey);
}