Comments (25)
@davidathompson ...hope this can be of help
Helper class
public static class CipherHelper
{
// This constant is used to determine the keysize of the encryption algorithm in bits.
// We divide this by 8 within the code below to get the equivalent number of bytes.
private const int Keysize = 256;
// This constant determines the number of iterations for the password bytes generation function.
private const int DerivationIterations = 1000;
public static string Encrypt(string plainText, string passPhrase)
{
// Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
// so that the same Salt and IV values can be used when decrypting.
var saltStringBytes = Generate256BitsOfRandomEntropy();
var ivStringBytes = Generate256BitsOfRandomEntropy();
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
var engine = new RijndaelEngine(256);
var blockCipher = new CbcBlockCipher(engine);
var cipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
var keyParam = new KeyParameter(keyBytes);
var keyParamWithIV = new ParametersWithIV(keyParam, ivStringBytes, 0, 32);
cipher.Init(true, keyParamWithIV);
var comparisonBytes = new byte[cipher.GetOutputSize(plainTextBytes.Length)];
var length = cipher.ProcessBytes(plainTextBytes, comparisonBytes, 0);
cipher.DoFinal(comparisonBytes, length);
// return Convert.ToBase64String(comparisonBytes);
return Convert.ToBase64String(saltStringBytes.Concat(ivStringBytes).Concat(comparisonBytes).ToArray());
}
}
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
var engine = new RijndaelEngine(256);
var blockCipher = new CbcBlockCipher(engine);
var cipher = new PaddedBufferedBlockCipher(blockCipher, new Pkcs7Padding());
var keyParam = new KeyParameter(keyBytes);
var keyParamWithIV = new ParametersWithIV(keyParam, ivStringBytes, 0, 32);
cipher.Init(false, keyParamWithIV);
var comparisonBytes = new byte[cipher.GetOutputSize(cipherTextBytes.Length)];
var length = cipher.ProcessBytes(cipherTextBytes, comparisonBytes, 0);
cipher.DoFinal(comparisonBytes, length);
//return Convert.ToBase64String(saltStringBytes.Concat(ivStringBytes).Concat(comparisonBytes).ToArray());
var nullIndex = comparisonBytes.Length - 1;
while (comparisonBytes[nullIndex] == (byte)0)
nullIndex--;
comparisonBytes = comparisonBytes.Take(nullIndex + 1).ToArray();
var result = Encoding.UTF8.GetString(comparisonBytes, 0, comparisonBytes.Length);
return result;
}
}
private static byte[] Generate256BitsOfRandomEntropy()
{
var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
using (var rngCsp = new RNGCryptoServiceProvider())
{
// Fill the array with cryptographically secure random bytes.
rngCsp.GetBytes(randomBytes);
}
return randomBytes;
}
}
Unit test
[Test]
public async Task CipherHelper_ShouldWork()
{
try
{
var value = "Secret to encrypt";
var passPhrase = "your pass phrase";
var encryptedValue = CipherHelper.Encrypt(value, passPhrase);
var decryptedValue = CipherHelper.Decrypt(encryptedValue, passPhrase);
Assert.IsTrue(value == decryptedValue);
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
}
from rijndael256.
@wmmihaa Thanks for this - seems to work flawlessly. For anyone wondering - it requires BouncyCastle.NetCore :)
from rijndael256.
+1
from rijndael256.
We have a desktop software using WPF and written a crypto library using RijndaelManaged using .NET FX 4.0 ~2010-2011 timeframe.
Now we are moving that code base to .NET 6, and discover this issue.
We are also Microsoft Partner and this is leaving us high and dry.
If MS supported RijndaelManaged with 256 bit blocksize, then it should have a upgrade route. We can definitely use the newer and ratified AES also, but what do we do with encrypted data at rest in files. We do have to support data/ config files from our older products and can not abandon that.
Right now the only working solution is to use BouncyCastle.NetCore.
When MS has 1000s of developers, how hard is it to support 256 bit blocksize giving us a native .NET solution instead of relying on a 3rd party library.
We plan to use it for "Reading old", and generate new files using new AES.
But do not like the concept no straightforward upgrade path.
I strongly vote for this to be added to .NET 6.
from rijndael256.
Reopening, since interest is spiking
from rijndael256.
.net core 2.0 and any example using a 256 block size will fail because you are trying to use AES which does not support that. This is block size not key size, a 256 key should work, a 256 block size will absolutely not work unless you write the actual rounds from scratch because the .net core team has emphatically refused to support Rijndael. You can try it by making a .net core console app and trying to decrypt anything that has been encrypted using Rijndael 256. It will fail as soon as you try and set that invalid block size. To further prove this remove the net45 section in the src, it should fail on all systems since it is AES (not tested but should).
from rijndael256.
@ByronAP can you provide an example illustrating how you're using a 256 block size with Rijndael256?
Rijndael256 currently supports:
- 128-128
- 192-128
- 256-128
N-256 isn't something I set out to support when I created this lib, but if a significant number of users would like to see it, I'm not opposed to investigating it's implementation. Are you certain you want to use 256 block size? It hasn't had nearly as much attention as 128 block size (which means it could have weaknesses that have yet to be discovered).
from rijndael256.
Thanks @wmmihaa and @suj87 , totally works. We were dead in the water before!
from rijndael256.
What version of .NET Core are you using @ByronAP? Can you provide an example?
from rijndael256.
I'm sure it is not all that common in .net however some libs in php use it along with some other functions so not having it in c# creates an interoperability impediment. I personally wouldn't bother because you have to write the whole thing yourself or rip some code from bouncy castle to make it work for what is essentially an edge case.
from rijndael256.
Closing, since there doesn't appear to be a great interest in this feature. Will re-open if that changes.
from rijndael256.
https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp
I'm using this easy and nice implementation that use 256 block size, could you have a look at it?
it's native (only system.security) and super fast to test
from rijndael256.
I'm using the same as @ciacco85 but doesn't work on .net core cause it's block size is 256 D:
from rijndael256.
@Gabriel-Espinoza https://stackoverflow.com/a/51947250/773165
from rijndael256.
I'm very interested, too. I have a library based created on .Net Standard. Importing it on .Net Framwork all goes right but using it on .Net Core I have problems.
from rijndael256.
I have a similar issue, as well. I have data stored that is encrypted using an initialization vector that requires a block size of 256. I'm trying to find a way to decrypt these values in .NET Core and cannot use 256.
from rijndael256.
Unfortunately, as of .NET Core 3.1, RijndaelManaged still does not support block sizes greater than 128. Looking at the source code, you can see .NET Core throws an exception if you try to use 192 or 256: https://github.com/dotnet/corefx/blob/release/3.1/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RijndaelImplementation.cs#L37
cc: @ciacco85 , @Gabriel-Espinoza
from rijndael256.
they have made it quite clear over the years that it will never be supported since it is not an official implementation :-(
from rijndael256.
+1 @JasonPierce are you still working on this?
from rijndael256.
@wmmihaa I'm keeping on eye on it. Unfortunately, as of .NET Core 3, it still does not support this. We can hope that they do add support in the new .NET 5 that is currently in Preview 1. Perhaps we'll get support for it at that time, since it is currently supported in .NET Framework 🤞
from rijndael256.
I believe it is necessary to provide 256 blocksize encryption and decryption.
We have an old windows application that used 256 blocksize to encrypt passwords in the database.
Now we are developing a web application version.
the problem is we can not use that data in the web application which is developing with asp.net core 3
from rijndael256.
Hey,
If .NET Core 3.1 still does not support 256 initialization vector why documentation does not reflect that?
Look at this:
//RijndaelManaged
// Legal min key size = 128
// Legal max key size = 256
// Legal min block size = 128
// Legal max block size = 256
Anybody can't get the same result! Why does the documentation is not refleting the truth?
from rijndael256.
Just discovered this, and it creates a huge block. I have to support decryption in .net core of values encrypted with .net framework using 256 bit. Arrrrgggg!!!
from rijndael256.
@wmmihaa Thank you! That is exactly what I needed. You saved me a ton of time.
from rijndael256.
@wmmihaa, thank you so much! Saved us a lot of time. Cheers! ❤️
from rijndael256.
Related Issues (12)
- Add configurable iterations for Rijndael and RijndaelEtM hashes
- specified padding mode is not valid for this algorithm HOT 2
- About support for .NET Core 1.0 HOT 2
- add-type A namespace cannot directly contain members such as fields or methods
- .NET Core 3.1 - Initialization vector 256 bits not supported HOT 1
- SecureString instead of String
- Rename Config to Settings
- Add Reset method to Settings
- Add unit tests for Rijndael.GenerateKey
- Add unit tests for Rng.GenerateRandomBytes
- Add CipherMode setting for Rijndael and RijndaelEtM
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rijndael256.