I'm using the "jose-jwt" library in C#. I'm able to get JWE encryption / decryption working for both RSA (RSA_OAEP_256, A256GCM) and EC (ECDH_ES_A256KW, A256GCM) in .NET 4.8. See sample code below.
However for .NET Core 3.1, only the RSA (RSA_OAEP_256, A256GCM) works. The "jose-jwt" library doesn't support EC (ECDH_ES_A256KW, A256GCM) in .NET Core.
Is it possible to use EC (ECDH_ES_A256KW, A256GCM) in .NET Core 3.1? If so, which library should I use? I've taken a look at the Microsoft library, but it appears EC (ECDH_ES_A256KW, A256GCM) is not support as well.
Microsoft.IdentityModel.JsonWebTokens;
Microsoft.IdentityModel.Tokens;
Note: I'm trying to encrypt a string using JWE, and not a claims list payload using JWT.
var payload = "some string";
// jose-jwt
// ECDH_ES_A256KW, A256GCM
var x = new byte[] { 4, 114, 29, 223, 58, 3, 191, 170, 67, 128, 229, 33, 242, 178, 157, 150, 133, 25, 209, 139, 166, 69, 55, 26, 84, 48, 169, 165, 67, 232, 98, 9 };
byte[] y = { 131, 116, 8, 14, 22, 150, 18, 75, 24, 181, 159, 78, 90, 51, 71, 159, 214, 186, 250, 47, 207, 246, 142, 127, 54, 183, 72, 72, 253, 21, 88, 53 };
var publicEccKey = EccKey.New(x, y, null, CngKeyUsages.KeyAgreement);
var token = JWT.Encode(payload, publicEccKey, JweAlgorithm.ECDH_ES_A256KW, JweEncryption.A256GCM);
//{
// "alg": "ECDH-ES+A256KW",
// "enc": "A256GCM",
// "epk": {
// "kty": "EC",
// "x": "Y-5VLvlizkiIkszi2Z8lKFwQUHrh6RbbIo0KOKm2clo",
// "y": "rducXOiOXDwchHTLfS03ZAQHzFRd4yiudAkzRsGLsvI",
// "crv": "P-256"
// }
//}
// jose-jwt
// RSA_OAEP_256, A256GCM
var publicRSAKey = new RSACryptoServiceProvider();
publicRSAKey.ImportParameters(new RSAParameters
{
// "n"
Modulus = Base64Url.Decode("0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"),
// "e"
Exponent = Base64Url.Decode("AQAB")
});
token = JWT.Encode(payload, publicRSAKey, JweAlgorithm.RSA_OAEP_256, JweEncryption.A256GCM);
//{
// "alg": "RSA-OAEP",
// "enc": "A256GCM"
//}
I have aproblem with testing my unzip method.
My unit test method is like:
[Fact]
public void UnzipData_CalledWithByteArrayParameter_ReturnsString()
{
_serializationService.CallerName = "";
byte[] array = new byte[] { 31, 139, 8, 0, 0, 0, 0, 0, 0, 11, 117, 205, 49, 15, 130, 48, 16, 134, 255, 255, 114, 43, 148, 220, 157, 165, 45, 55, 234, 204, 98, 216, 140, 3, 9, 23, 37, 209, 18, 67, 53, 38, 134, 255, 46, 168, 139, 3, 243, 247, 189, 121, 14, 47, 232, 159, 32, 148, 195, 110, 136, 73, 99, 170, 135, 78, 47, 32, 47, 136, 237, 85, 65, 160, 214, 211, 185, 141, 144, 195, 163, 31, 251, 52, 126, 174, 93, 155, 150, 137, 145, 130, 65, 103, 152, 26, 44, 165, 172, 4, 109, 65, 155, 210, 57, 79, 25, 178, 32, 206, 213, 114, 221, 235, 237, 174, 99, 210, 238, 175, 129, 105, 202, 191, 56, 175, 226, 219, 97, 13, 174, 12, 178, 97, 219, 80, 16, 14, 98, 185, 32, 31, 188, 117, 62, 67, 90, 133, 127, 205, 12, 31, 223, 154, 207, 196, 62, 247, 0, 0, 0 };
string result = _serializationService.UnzipData(array);
Assert.False(result.Length == 0);
Assert.True(result.Length > array.Length);
}
but result variable is null. Sut based on this answer:
public string UnzipData(byte[] bytes)
{
LoadDictionaries();
CallerName = _messageService.GetCallerName();
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
try
{
using (var gs = new GZipStream(msi, CompressionMode.Decompress))
{
CopyTo(gs, mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
}
catch (Exception e)
{
_logger.Error(e, MessagesError[CallerName]);
return null;
}
}
}
and
public static void CopyTo(Stream src, Stream dest)
{
byte[] bytes = new byte[4096];
int cnt;
while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
{
dest.Write(bytes, 0, cnt);
}
}
The main problem is that I am not quite sure how to pass byte[] compressed by GZipStream data in my unit test.
As I belive, in test preparation I am not supposed to do something like this? Is not it breaking testability?
[Fact]
public void UnzipData_CalledWithByteArrayParameter_ReturnsString()
{
_serializationService.CallerName = "";
string someString = "fdfsdfsdfsdfsf";
byte[] array = _serializationService.ZipData(someString); //using compress method first????
string result = _serializationService.UnzipData(array);
Assert.False(result.Length == 0);
Assert.True(result.Length > array.Length);
}
Or maybe I can?
ZipData method:
public byte[] ZipData(string data)
{
LoadDictionaries();
CallerName = _messageService.GetCallerName();
var bytes = Encoding.UTF8.GetBytes(data);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
try
{
using (var gs = new GZipStream(mso, CompressionMode.Compress))
{
CopyTo(msi, gs);
}
byte[] toReturn = mso.ToArray();
return toReturn;
}
catch (Exception e)
{
_logger.Error(e, MessagesError[CallerName]);
return null;
}
}
}
And compressing method returns me:
new byte[] { 31, 139, 8, 0, 0, 0, 0, 0, 0, 11, 125, 206, 61, 11, 194, 48, 16, 6, 224, 255, 114, 171, 77, 185, 94, 62, 74, 179, 234, 234, 34, 221, 196, 33, 144, 27, 2, 53, 197, 38, 138, 80, 250, 223, 141, 90, 16, 151, 194, 45, 7, 247, 222, 243, 158, 103, 8, 79, 176, 77, 5, 251, 49, 102, 142, 249, 56, 122, 30, 192, 206, 16, 221, 149, 193, 194, 193, 69, 7, 21, 120, 151, 223, 27, 97, 99, 4, 106, 129, 166, 39, 178, 100, 202, 212, 168, 100, 139, 170, 219, 33, 189, 196, 245, 244, 196, 183, 59, 167, 204, 254, 47, 3, 203, 182, 125, 61, 218, 240, 166, 129, 35, 151, 63, 143, 144, 66, 78, 159, 110, 63, 93, 9, 236, 4, 233, 30, 181, 45, 5, 164, 172, 165, 54, 70, 181, 155, 250, 154, 41, 250, 229, 5, 222, 237, 15, 25, 239, 0, 0, 0 }
from string:
[{\"ix\":1,\"ContentModel\":{\"name\":\"Dana\",\"date\":\"2016-05-06T22:26:26.0437049+02:00\",\"dateRequested\":\"2016-05-06\"}},{\"ix\":2,\"ContentModel\":{\"name\":\"Darlene\",\"visits\":1,\"date\":\"2014-09-25T05:22:33.3566479+02:00\",\"dateRequested\":\"2014-09-25\"}}]
UPDATED TEST
[Fact]
public void UnzipData_CalledWithByteArrayParameter_ReturnsString()
{
//string _jsonExample i converted in txtwizard.net/compression
string _jsonExample = "[{\"ix\":1,\"ContentModel\":{\"name\":\"Dana\",\"date\":\"2016-05-06T22:26:26.0437049+02:00\",\"dateRequested\":\"2016-05-06\"}},{\"ix\":2,\"ContentModel\":{\"name\":\"Darlene\",\"visits\":1,\"date\":\"2014-09-25T05:22:33.3566479+02:00\",\"dateRequested\":\"2014-09-25\"}}]";
var base64String = "H4sIAAAAAAAA/4WOPwvCMBDFv0tWm3K9/CnNqquLdDMOgdwQqCmaKIL0uxu1irgUbjjevXfvt79bFm6WmaaybD3GTDFvR09DkcopuiOVzbKNi86y4vEuvxWERnNQHHSPaFCXqUGKFmS3AjQAX/uOThdKmfxfzrJpqj79uNR/HijS6+c1pJDTzPzLIzl0HFUPyhQkIWqhtJbtIs+ce/IcHmtZn30RAQAA";
byte[] array = Convert.FromBase64String(base64String);
_serializationService.CallerName = "";
string result = _serializationService.UnzipData(array);
Assert.Equals(result, _jsonExample); //not equal, added extra backslashes
Assert.Equal("SomeMethod", _serializationService.CallerName);
_messageServiceMock.Verify(m => m.GetCallerName(It.IsAny<string>()), Times.Once);
}
Your source data in:-
byte[] array = new byte[] { 31, 139, 8, 0, 0, 0, 0, 0, 0, 11, 117, 205, 49, 15, 130, 48, 16, 134, 255, 255, 114, 43, 148, 220, 157, 165, 45, 55, 234, 204, 98, 216, 140, 3, 9, 23, 37, 209, 18, 67, 53, 38, 134, 255, 46, 168, 139, 3, 243, 247, 189, 121, 14, 47, 232, 159, 32, 148, 195, 110, 136, 73, 99, 170, 135, 78, 47, 32, 47, 136, 237, 85, 65, 160, 214, 211, 185, 141, 144, 195, 163, 31, 251, 52, 126, 174, 93, 155, 150, 137, 145, 130, 65, 103, 152, 26, 44, 165, 172, 4, 109, 65, 155, 210, 57, 79, 25, 178, 32, 206, 213, 114, 221, 235, 237, 174, 99, 210, 238, 175, 129, 105, 202, 191, 56, 175, 226, 219, 97, 13, 174, 12, 178, 97, 219, 80, 16, 14, 98, 185, 32, 31, 188, 117, 62, 67, 90, 133, 127, 205, 12, 31, 223, 154, 207, 196, 62, 247, 0, 0, 0 };
Is not valid Gzip data, and your method is throwing an InvalidDataException where you are returning null.
Otherwise, your method works fine with correct input data.
Using the core parts of your provided code to create a minimal example of the subject under test
public class Subject {
public byte[] ZipData(string data) {
//LoadDictionaries();
//CallerName = _messageService.GetCallerName();
var bytes = Encoding.UTF8.GetBytes(data);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream()) {
try {
using (var gs = new GZipStream(mso, CompressionMode.Compress)) {
msi.CopyTo(gs);
}
byte[] toReturn = mso.ToArray();
return toReturn;
} catch (Exception e) {
// _logger.Error(e, MessagesError[CallerName]);
return Array.Empty<byte>();
}
}
}
public string UnzipData(byte[] bytes) {
//LoadDictionaries();
//CallerName = _messageService.GetCallerName();
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream()) {
try {
using (var gs = new GZipStream(msi, CompressionMode.Decompress)) {
gs.CopyTo(mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
} catch (Exception e) {
//_logger.Error(e, MessagesError[CallerName]);
return string.Empty;
}
}
}
}
The following test behaves as expected when exercised
[TestClass]
public class MyTestClass {
[TestMethod]
public void UnzipData_CalledWithByteArrayParameter_ReturnsString() {
//Arrange
var _serializationService = new Subject();
string expected = "[{\"ix\":1,\"ContentModel\":{\"name\":\"Dana\",\"date\":\"2016-05-06T22:26:26.0437049+02:00\",\"dateRequested\":\"2016-05-06\"}},{\"ix\":2,\"ContentModel\":{\"name\":\"Darlene\",\"visits\":1,\"date\":\"2014-09-25T05:22:33.3566479+02:00\",\"dateRequested\":\"2014-09-25\"}}]";
byte[] array = _serializationService.ZipData(expected);
//Act
string actual = _serializationService.UnzipData(array);
//Assert
actual.Should().NotBeNull()
.And.Be(expected);
}
}
Note the changes made to the used functions. Mainly not returning null which can bring its own complications.
Your assertions were also in accurate since the string and byte array lengths wont match given the zip process.
In my opinion zipping the data as part of arranging the test does not break isolation since the zip is not what is being tested (technically).
You could easily have rewritten the zip code again manually in the test to ensure you have correct data to supply to the member under test but why repeat existing functionality.
That would not be very DRY.
The assumption here would be that the zip functionality would have also had its own isolated unit test. If its test failed then that member is already covered.
I have a nodejs buffer:
var buffer = new Buffer([33,49,0,32,0,0,0,0,2,230,69,56,0,1,125,181,99,99,136,122,92,1,99,196,231,90,205,20,75,233,5,103]);
var value = buffer.readUInt32BE(8);
//value == 48645432
I tried read value from C#:
var buffer = new byte[]{33,49,0,32,0,0,0,0,2,230,69,56,0,1,125,181,99,99,136,122,92,1,99,196,231,90,205,20,75,233,5,103};
var value = BitConverter.ToUInt32(buffer, 8)
//value == 944104962
So, I need get value 48645432 from my C# code.
How can I write a method from C# return exact value like readUInt32BE from nodejs?
EDIT: How to get little endian data from big endian in c# using bitConverter.ToInt32 method? not resolve my problem
I resolve my problem
var buffer = new byte[] { 33, 49, 0, 32, 0, 0, 0, 0, 2, 230, 69, 56, 0, 1, 125, 181, 99, 99, 136, 122, 92, 1, 99, 196, 231, 90, 205, 20, 75, 233, 5, 103 };
var value = BitConverter.ToUInt32(buffer, 8);
var rs = BitConverter.ToUInt32(BitConverter.GetBytes(value).Reverse().ToArray(), 0);
//rs = 48645432
Given I am setting the KeySize to be 192, when I am encrypting some data by doing the following:
static void Main()
{
var querystrings = "dataToEncrypt";
byte[] keyvalue = new byte[] { 241, 205, 121, 123, 109, 246, 247, 103, 31, 225, 167, 220, 247, 119, 247, 119, 78, 125, 127, 167, 156, 213, 230, 250, };
byte[] ivvalue = new byte[] { 194, 177, 79, 213, 87, 46, 213, 189, 243, 169, 32, 13, 217, 62, 34, 170, };
byte[] querystringBytes = Encoding.UTF8.GetBytes(querystrings);
using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
{
rijndaelManaged.BlockSize = 128;
rijndaelManaged.KeySize = 192;
rijndaelManaged.IV = ivvalue;
rijndaelManaged.Key = keyvalue;
rijndaelManaged.Padding = PaddingMode.PKCS7;
rijndaelManaged.Mode = CipherMode.CBC;
using (MemoryStream memoryStream = new MemoryStream())
{
ICryptoTransform transform = rijndaelManaged.CreateEncryptor();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(querystringBytes, 0, querystringBytes.Length);
cryptoStream.FlushFinalBlock();
var output = Convert.ToBase64String(memoryStream.ToArray());
Console.WriteLine($"{output}");
Console.ReadKey();
}
}
}
}
The data encrypts as I'd expect as the IV and encryption key are 128 bits and 192 bits long respectively. If however I set the encryption key to be 128 bits long (for arguments sake, lets use the same byte array as the IV) i.e.
static void Main()
{
var querystrings = "dataToEncrypt";
byte[] keyvalue = new byte[] { 194, 177, 79, 213, 87, 46, 213, 189, 243, 169, 32, 13, 217, 62, 34, 170, };
byte[] ivvalue = new byte[] { 194, 177, 79, 213, 87, 46, 213, 189, 243, 169, 32, 13, 217, 62, 34, 170, };
byte[] querystringBytes = Encoding.UTF8.GetBytes(querystrings);
using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
{
rijndaelManaged.BlockSize = 128;
rijndaelManaged.KeySize = 192;
rijndaelManaged.IV = ivvalue;
rijndaelManaged.Key = keyvalue;
rijndaelManaged.Padding = PaddingMode.PKCS7;
rijndaelManaged.Mode = CipherMode.CBC;
using (MemoryStream memoryStream = new MemoryStream())
{
ICryptoTransform transform = rijndaelManaged.CreateEncryptor();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(querystringBytes, 0, querystringBytes.Length);
cryptoStream.FlushFinalBlock();
var output = Convert.ToBase64String(memoryStream.ToArray());
Console.WriteLine($"{output}");
Console.ReadKey();
}
}
}
}
This will still encrypt without exception. My question is:
What does the KeySize do internally as it's accepting a 128 bit encryption key when I am explicitly setting the KeySize as 192? Why is no exception occurring?
The Key and KeySize properties of the RijndaelManaged class are inherited from the base SymmetricAlgorithm class. The precise behavior of these properties isn't well documented in MSDN Library, but if you look at the SymmetricAlgorithm source code, you'll see that the Key and KeySize properties interact with each other as follows:
When you set the Key property, the KeySize property is automatically set to the length of the new key in bits.
When you set the KeySize property, the existing Key is cleared out (and a new random key is automatically generated the next time Key is accessed).
Therefore, if you're setting the Key property, there's no point in setting the KeySize property beforehand.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 9 years ago.
Improve this question
I have this byte[] that represent IPv4 packet:
byte[] arr = { 0, 48, 136, 21, 69, 131, 0, 24, 231, 253, 174, 161, 8, 0, 69, 0, 0, 52, 2, 31, 64, 0, 128, 6, 230, 22, 212, 25, 99, 74, 202, 177, 16, 121, 194, 156, 0, 119, 160, 128, 75, 200, 249, 141, 210, 78, 80, 24, 64, 252, 130, 182, 0, 0, 65, 82, 84, 73, 67, 76, 69, 32, 51, 52, 13, 10 };
And i want to calculate the IPV4 address
Here's a simple parser to examine your byte array:
void Main()
{
byte[] arr = { 0, 48, 136, 21, 69, 131, 0, 24, 231, 253, 174, 161, 8, 0, 69, 0, 0, 52, 2, 31, 64, 0, 128, 6, 230, 22, 212, 25, 99, 74, 202, 177, 16, 121, 194, 156, 0, 119, 160, 128, 75, 200, 249, 141, 210, 78, 80, 24, 64, 252, 130, 182, 0, 0, 65, 82, 84, 73, 67, 76, 69, 32, 51, 52, 13, 10 };
var stream = new MemoryStream(arr, 0, arr.Length);
var reader = new BinaryReader(stream);
Print("Version and header length", reader.ReadByte());
Print("Diff services", reader.ReadByte());
Print("Total length", IPAddress.NetworkToHostOrder(reader.ReadInt16()));
Print("ID", IPAddress.NetworkToHostOrder(reader.ReadInt16()));
Print("Flags and offset", IPAddress.NetworkToHostOrder(reader.ReadInt16()));
Print("TTL", reader.ReadByte());
Print("Protocol", reader.ReadByte());
Print("Checksum", reader.ReadInt16());
Print("Source IP", new IPAddress((int) reader.ReadInt32()));
Print("Destination IP", new IPAddress((int) reader.ReadInt32()));
}
This produces this output:
Version and header length = 0
Diff services = 48
Total length = -30699
ID = 17795
Flags and offset = 24
TTL = 231
Protocol = 253
Checksum = -24146
Source IP = 8.0.69.0
Destination IP = 0.52.2.31
This doesn't seem very right (negative length/checksum? + the protocol should return '6' for TCP or '8' for UDP). You might want to verify your data is correct first.
I wrote this up with code from a tiny project of mine which might help you with future issues. Definitely look at the packet layout on wikipedia, you'll need it with DNS/UDP as well.