i have next code to convert ADPCM wav in PCM wave how you can do without intermediate storage file to disk here WaveFileWriter.CreateWaveFile("D:\\pcm16000.wav", upsampler);
public static byte[] ADPcmToPcm(string waveFileName, int bitRate = 128)
{
using (var reader = new WaveFileReader(waveFileName))
using (var converter = WaveFormatConversionStream.CreatePcmStream(reader))
using (var upsampler = new WaveFormatConversionStream(new WaveFormat(16000, converter.WaveFormat.Channels), converter))
{
WaveFileWriter.CreateWaveFile("D:\\pcm16000.wav", upsampler);
FileStream fs = new FileStream("d:\\pcm16000.wav", FileMode.Open, FileAccess.Read);
byte [] bytes = new byte[fs.Length];
int bytesToRead = (int)fs.Length;
int bytesRead = 0;
while (bytesToRead > 0)
{
int n = fs.Read(bytes, bytesRead, bytesToRead);
if (n == 0) break;
bytesRead += n;
bytesToRead -= n;
}
bytesToRead = bytes.Length;
return bytes;
}
}
For some time I've been a bit desperately trying to implement a TLS 1.1 in my application. The reason behind this is the usage of SocketType.Raw sockets, so no SslStream or other higher-level classes are available to me.
So far I'm stuck at Finished message in TLS handshake protocol - keep on receiving bad_record_mac(20) in server response. Cipher suite is 0x0005 - TLS_RSA_WITH_RC4_128_SHA.
Here's some sample code on what's happening:
byte[] client_random, server_random = new byte[28];
byte[] pre_master_secret, master_secret;
byte[] client_write_MAC_secret, server_write_MAC_secret, client_write_key, server_write_key;
byte[] handshake_messages, verify_data;
RSACryptoServiceProvider rsa;
List<X509Certificate2> certificates = new List<X509Certificate2>();
//certificates are added
rsa = (RSACryptoServiceProvider)certificates.First().PublicKey.Key;
private byte[] ClientKeyExchange()
{
pre_master_secret = new byte[48];
(new Random()).NextBytes(pre_master_secret);
//version 0302 for TLS 1.1
pre_master_secret[0] = 3;
pre_master_secret[1] = 2;
byte[] cryptedData = rsa.Encrypt(pre_master_secret, false);
//"1603020086"
string tmp_string = "100000820080" + Utils.BitConverter.ToString(cryptedData).Replace("-", "");
AddHandShakeData(Utils.BitConverter.StringToByteArray(tmp_string));
tmp_string =
"1603020086"
+ tmp_string
+ "140302000101" //Cipher Change Spec
+ "";
return Utils.BitConverter.StringToByteArray(tmp_string);
}
private void ComputeMasterSecret()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("master secret", Encoding.ASCII));
byte[] seed = new byte[client_random.Length + server_random.Length];
Buffer.BlockCopy(client_random, 0, seed, 0, client_random.Length);
Buffer.BlockCopy(server_random, 0, seed, client_random.Length, server_random.Length);
master_secret = PRF(pre_master_secret, label, seed, 48);
}
private void ComputeKeys()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("key expansion", Encoding.ASCII));
byte[] seed = new byte[client_random.Length + server_random.Length];
Buffer.BlockCopy(client_random, 0, seed, 0, client_random.Length);
Buffer.BlockCopy(server_random, 0, seed, client_random.Length, server_random.Length);
byte[] key_material = PRF(master_secret, label, seed, 72);
client_write_MAC_secret = new byte[20];
Buffer.BlockCopy(key_material, 0, client_write_MAC_secret, 0, 20);
server_write_MAC_secret = new byte[20];
Buffer.BlockCopy(key_material, 20, server_write_MAC_secret, 0, 20);
client_write_key = new byte[16];
Buffer.BlockCopy(key_material, 40, client_write_key, 0, 16);
server_write_key = new byte[16];
Buffer.BlockCopy(key_material, 56, server_write_key, 0, 16);
}
private void ComputeVerifyData()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("client finished", Encoding.ASCII));
SHA1 sha1 = SHA1.Create();
MD5 md5 = MD5.Create();
md5.ComputeHash(handshake_messages);
sha1.ComputeHash(handshake_messages);
byte[] seed = new byte[md5.HashSize / 8 + sha1.HashSize / 8];
Buffer.BlockCopy(md5.Hash, 0, seed, 0, md5.HashSize / 8);
Buffer.BlockCopy(sha1.Hash, 0, seed, md5.HashSize / 8, sha1.HashSize / 8);
verify_data = PRF(master_secret, label, seed, 12);
}
private byte[] PRF(byte[] secret, byte[] label, byte[] seed, int output_size)
{
int md5_iterations = (int)Math.Ceiling((double)output_size / 16),
sha1_iterations = (int)Math.Ceiling((double)output_size / 20);
byte[] md5_data = new byte[output_size],
sha1_data = new byte[output_size];
//особое колдунство для нечетного числа
byte[] secret_1 = new byte[(int)Math.Ceiling((double)secret.Length / 2)],
secret_2 = new byte[(int)Math.Ceiling((double)secret.Length / 2)];
Buffer.BlockCopy(secret, 0, secret_1, 0, secret_1.Length);
Buffer.BlockCopy(secret, secret.Length / 2, secret_2, 0, secret_2.Length);
byte[] A = new byte[label.Length + seed.Length];
Buffer.BlockCopy(label, 0, A, 0, label.Length);
Buffer.BlockCopy(seed, 0, A, label.Length, seed.Length);
byte[] tmp = new byte[md5_iterations * 16];
//A(1) ?
//A = P_MD5(secret_1, A);
for (int i = 0; i < md5_iterations; i++)
{
A = P_MD5(secret_1, A);
Buffer.BlockCopy(A, 0, tmp, i * A.Length, A.Length);
}
Buffer.BlockCopy(tmp, 0, md5_data, 0, md5_data.Length); //output_size = md5_data.Length
tmp = new byte[sha1_iterations * 20];
//does it have to start with A(1) ?
//A = P_SHA1(secret_2, A);
for (int i = 0; i < sha1_iterations; i++)
{
A = P_SHA1(secret_2, A);
Buffer.BlockCopy(A, 0, tmp, i * A.Length, A.Length);
}
Buffer.BlockCopy(tmp, 0, sha1_data, 0, sha1_data.Length); //output_size = sha1_data.Length
for (int i = 0; i < output_size; i++)
md5_data[i] = (byte)(md5_data[i] ^ sha1_data[i]);
return md5_data;
}
private byte[] P_MD5(byte[] secret /*это ключ?*/, byte[] seed /*это дата?*/)
{
HMACMD5 HMD5 = new HMACMD5(secret);
HMD5.ComputeHash(seed);
return HMD5.Hash;
}
private byte[] P_SHA1(byte[] secret /*это ключ?*/, byte[] seed /*это дата?*/)
{
HMACSHA1 HSHA1 = new HMACSHA1(secret);
HSHA1.ComputeHash(seed);
return HSHA1.Hash;
}
private byte[] MAC(byte[] secret, byte[] data)
{
byte[] secret_64 = new byte[64];
Buffer.BlockCopy(secret, 0, secret_64, 0, secret.Length);
for (int i = 0; i < 64; i++)
secret_64[i] = (byte)(secret_64[i] ^ (byte)54);
byte[] xor_output_data = new byte[64 + data.Length];
Buffer.BlockCopy(secret_64, 0, xor_output_data, 0, 64);
Buffer.BlockCopy(data, 0, xor_output_data, 64, data.Length);
SHA1 sha1 = SHA1.Create();
sha1.ComputeHash(xor_output_data);
secret_64 = new byte[64];
Buffer.BlockCopy(secret, 0, secret_64, 0, secret.Length);
for (int i = 0; i < 64; i++)
secret_64[i] = (byte)(secret_64[i] ^ (byte)92);
xor_output_data = new byte[64 + sha1.HashSize / 8];
Buffer.BlockCopy(secret_64, 0, xor_output_data, 0, 64);
Buffer.BlockCopy(sha1.Hash, 0, xor_output_data, 64, sha1.HashSize / 8);
sha1.ComputeHash(xor_output_data);
return sha1.Hash;
}
public void RC4(ref Byte[] bytes, Byte[] key)
{
Byte[] s = new Byte[128];
Byte[] k = new Byte[128];
Byte temp;
int i, j;
for (i = 0; i < 128; i++)
{
s[i] = (Byte)i;
k[i] = key[i % key.GetLength(0)];
}
j = 0;
for (i = 0; i < 128; i++)
{
j = (j + s[i] + k[i]) % 128;
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
i = j = 0;
for (int x = 0; x < bytes.GetLength(0); x++)
{
i = (i + 1) % 128;
j = (j + s[i]) % 128;
temp = s[i];
s[i] = s[j];
s[j] = temp;
int t = (s[i] + s[j]) % 128;
bytes[x] ^= s[t];
}
}
Obviously, reading such a bunch of code ain't being the best way to spend your time, so I'd like to add some questions that, hopefully, can help a lot:
HMAC_MD5 and HMAC_SHA1 - in .Net implementation they take key and they take input byte[] to compute hash from. According to RFC4346:
First, we define a data expansion function, P_hash(secret, data)
which uses a single hash function to expand a secret and seed into an
arbitrary quantity of output:
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...
Where + indicates concatenation.
A() is defined as:
A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))
What is seed? Is it data we compute hash from? Secret = key, so far I understand. Also, do we start P_hash with A(1)?
Thanks in advance!
Seed is Client_random + Server_random. You need to preserve them from preceding steps of the handshake, the client_hello and server_hello.
A(0) = seed
A(i) = HMAC_hash(secret,A(i-1)) for i>0
The output of the A() function consists of A(1), A(2), A(3)...
This question is a follow-up of this Question
I have written a small method to fill a byte[] just like the MemoryStream :
public static Stream FillWithPadding(Stream MS, int Count)
{
byte[] buffer = new byte[64];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = 0xFF;
}
while (Count > buffer.Length)
{
MS.Write(buffer, 0, buffer.Length);
Count -= buffer.Length;
}
MS.Write(buffer, 0, Count);
return MS;
}
public static byte[] FillWithPadding(byte[] Buffer, int Count)
{
using (MemoryStream MS = new MemoryStream())
{
MS.Write(Buffer, 0, Buffer.Length);
MemoryStream msw = FillWithPadding(MS, Count) as MemoryStream;
return msw.GetBuffer();
}
}
This code is not working!!
Instead it is creating 0xFF + 0x00 at the End!
Can anyone Please clear-up, Why this does not work??
MemoryStream.GetBuffer() returns internal byte array that MemoryStream uses to store data. Initially it filled with 0, and filled up to stream length by Write's.
Most likely you want to use MemoryStream.ToArray() instead that returns copy of the buffer truncated to actual length.
That's the position in the Stream Now.
use MS.Position = 0 before Write.
public static Stream FillWithPadding(Stream MS, int Count)
{
byte[] buffer = new byte[64];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = 0xFF;
}
MS.Position = 0;
while (Count > buffer.Length)
{
MS.Write(buffer, 0, buffer.Length);
Count -= buffer.Length;
}
MS.Write(buffer, 0, Count);
return MS;
}
I currently got this script, which compresses byte arrays.
But I need it rewritten, so it can compress triple byte arrays [,,]
Thanks!
public static byte[] Compress(byte[] buffer)
{
MemoryStream ms = new MemoryStream();
GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true);
zip.Write(buffer, 0, buffer.Length);
zip.Close();
ms.Position = 0;
MemoryStream outStream = new MemoryStream();
byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);
byte[] gzBuffer = new byte[compressed.Length + 4];
Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
return gzBuffer;
}
public static byte[] Decompress(byte[] gzBuffer)
{
MemoryStream ms = new MemoryStream();
int msgLength = BitConverter.ToInt32(gzBuffer, 0);
ms.Write(gzBuffer, 4, gzBuffer.Length - 4);
byte[] buffer = new byte[msgLength];
ms.Position = 0;
GZipStream zip = new GZipStream(ms, CompressionMode.Decompress);
zip.Read(buffer, 0, buffer.Length);
return buffer;
}
Update: I rewrote the code, it is running much faster now and the code is cleaner. Just tested it with some random data (see end of this post).
The Compression method:
public static byte[] Compress(byte[, ,] uncompressed)
{
if (uncompressed == null)
throw new ArgumentNullException("uncompressed",
"The given array is null!");
if (uncompressed.LongLength > (long)int.MaxValue)
throw new ArgumentException("The given array is to large!");
using (MemoryStream ms = new MemoryStream())
using (GZipStream gzs = new GZipStream(ms, CompressionMode.Compress))
{
// Save sizes of the dimensions
for (int dim = 0; dim < 3; dim++)
gzs.Write(BitConverter.GetBytes(
uncompressed.GetLength(dim)), 0, sizeof(int));
// Convert byte[,,] to byte[] by just blockcopying it
// I know, some pointer-magic/unmanaged cast wouldnt
// have to copy it, but its cleaner this way...
byte[] data = new byte[uncompressed.Length];
Buffer.BlockCopy(uncompressed, 0, data, 0, uncompressed.Length);
// Write the data to the stream to compress it
gzs.Write(data, 0, data.Length);
gzs.Close();
// Get the compressed byte array back
return ms.ToArray();
}
}
The Decompression method:
public static byte[, ,] Decompress(byte[] compressed)
{
if (compressed == null)
throw new ArgumentNullException("compressed",
"Data to decompress cant be null!");
using (MemoryStream ms = new MemoryStream(compressed))
using (GZipStream gzs = new GZipStream(ms, CompressionMode.Decompress))
{
// Read the header and restore sizes of dimensions
byte[] dimheader = new byte[sizeof(int) * 3];
gzs.Read(dimheader, 0, dimheader.Length);
int[] dims = new int[3];
for (int j = 0; j < 3; j++)
dims[j] = BitConverter.ToInt32(dimheader, sizeof(int) * j);
// Read the data into a buffer
byte[] data = new byte[dims[0] * dims[1] * dims[2]];
gzs.Read(data, 0, data.Length);
// Copy the buffer to the three-dimensional array
byte[, ,] uncompressed = new byte[dims[0], dims[1], dims[2]];
Buffer.BlockCopy(data, 0, uncompressed, 0, data.Length);
return uncompressed;
}
}
The test code:
Random rnd = new Random();
// Create a new randomly big array, fill it with random data
byte[, ,] uncomp = new byte[rnd.Next(70, 100),
rnd.Next(70, 100), rnd.Next(70, 100)];
for (int x = 0; x < uncomp.GetLength(0); x++)
for (int y = 0; y < uncomp.GetLength(1); y++)
for (int z = 0; z < uncomp.GetLength(2); z++)
uncomp[x, y, z] = (byte)rnd.Next(30, 35);
// Compress and Uncompress again
Stopwatch compTime = new Stopwatch(), uncompTime = new Stopwatch();
compTime.Start();
byte[] comp = Compress(uncomp);
compTime.Stop();
uncompTime.Start();
byte[, ,] uncompagain = Decompress(comp);
uncompTime.Stop();
// Assert all dimension lengths and contents are equal
for (int j = 0; j < 3; j++)
Debug.Assert(uncomp.GetLength(j) == uncompagain.GetLength(j));
for (int x = 0; x < uncomp.GetLength(0); x++)
for (int y = 0; y < uncomp.GetLength(1); y++)
for (int z = 0; z < uncomp.GetLength(2); z++)
Debug.Assert(uncomp[x, y, z] == uncompagain[x, y, z]);
Console.WriteLine(string.Format("Compression: {0}ms, " +
"Decompression: {1}ms, Ratio: {2}% ({3}/{4} bytes)",
compTime.ElapsedMilliseconds, uncompTime.ElapsedMilliseconds,
(int)((double)comp.LongLength / (double)uncomp.LongLength * 100),
comp.LongLength, uncomp.LongLength));
Output, for example:
Compression: 77ms, Decompression: 23ms, Ratio: 41% (191882/461538 bytes)
Can anyone see any obvious holes in my logic here. Basically I need to break up a byte array into chunks of 10,000 before sending it out:
byte [] bytes = GetLargePieceOfData();
Stream stream = CreateAStream();
if (bytes.Length > 10000)
{
int pos = 0;
int chunkSize = 10000;
while (pos < bytes.Length)
{
if (pos + chunkSize > bytes.Length)
chunkSize = bytes.Length - pos;
stream.Write(bytes, pos, chunkSize);
pos += chunkSize;
}
}
else
{
stream.Write(bytes, 0, bytes.Length);
}
Everything seems to be in order, but the outermost if statement is really redundant, as the following code
int pos = 0;
int chunkSize = 10000;
while (pos < bytes.Length)
{
if (pos + chunkSize > bytes.Length)
chunkSize = bytes.Length - pos;
stream.Write(bytes, pos, chunkSize);
pos += chunkSize;
}
will also handle the case where the array is smaller than the chunk size.