// Hash-based Message Authentication Codes: generates a code for verifying the sender of a message and the like public static byte[] HMAC(byte[] key, byte[] message, HashFunction func, int blockSizeBytes) { if (key.Length > blockSizeBytes) { key = func(key); } else if (key.Length < blockSizeBytes) { byte[] b = new byte[blockSizeBytes]; Array.Copy(key, b, key.Length); key = b; } byte[] o_key_pad = new byte[blockSizeBytes]; // Outer padding byte[] i_key_pad = new byte[blockSizeBytes]; // Inner padding for (int i = 0; i < blockSizeBytes; ++i) { // Combine padding with key o_key_pad[i] = (byte)(key[i] ^ 0x5c); i_key_pad[i] = (byte)(key[i] ^ 0x36); } return(func(Support.Concatenate(o_key_pad, func(Support.Concatenate(message, i_key_pad))))); }
// Deserialize RSA data (for key distribution (but the other end (how many parentheses deep can I go?))) public static RSA Deserialize(byte[] function, out int read) { byte[][] rd = Support.DeserializeBytes(function, 2); read = rd[0].Length + rd[1].Length + 8; return(new RSA(rd[0], rd[1])); }
// Serialize (for public key distribution) public byte[] Serialize() => Support.SerializeBytes(new byte[][] { e.ToByteArray(), n.ToByteArray() });
public static byte[] FromHeaded(byte[] msg, int offset) => msg.SubArray(offset + 4, offset + 4 + Support.ReadInt(msg, offset));
protected internal bool SyncListener(ref bool cryptoEstablished, ref int mLen, out bool acceptedData, Queue <byte> ibuf, byte[] buffer) { if (cryptoEstablished) { lock (messageBuffer) { foreach (byte[] message in messageBuffer) { Connection.Send(NetSupport.WithHeader(message)); } messageBuffer.Clear(); } } if (acceptedData = Connection.Available > 0) { int read = Connection.Receive(buffer); ibuf.EnqueueAll(buffer, 0, read); } if (mLen == 0 && ibuf.Count >= 4) { mLen = Support.ReadInt(ibuf.Dequeue(4), 0); } if (mLen != 0 && ibuf.Count >= mLen) { // Got a full message. Parse! byte[] message = ibuf.Dequeue(mLen); if (!cryptoEstablished) { if (ServerSide) { try { if (Crypto == null) { Crypto = Rijndael128.Deserialize(decrypt.Decrypt(message), out int _); } else { CBC = new PCBC(Crypto, decrypt.Decrypt(message)); } } catch (Exception) { Console.WriteLine("A fatal error ocurrd when attempting to establish a secure channel! Stopping..."); Thread.Sleep(5000); Environment.Exit(-1); } } else { // Reconstruct RSA object from remote public keys and use it to encrypt our serialized AES key/iv RSA asymm = RSA.Deserialize(message, out int _); Connection.Send(NetSupport.WithHeader(asymm.Encrypt(Crypto.Serialize()))); Connection.Send(NetSupport.WithHeader(asymm.Encrypt(CBC.IV))); } if (CBC != null) { cryptoEstablished = true; onConn(this); } } else { // Decrypt the incoming message byte[] read = Crypto.Decrypt(message); // Read the decrypted message length int mlenInner = Support.ReadInt(read, 0); // Send the message to the handler and get a response string response = handler(read.SubArray(4, 4 + mlenInner).ToUTF8String(), out bool live); // Send the response (if given one) and drop the connection if the handler tells us to if (response != null) { Connection.Send(NetSupport.WithHeader(Crypto.Encrypt(NetSupport.WithHeader(response.ToUTF8Bytes())))); } if (!live) { Running = false; try { Connection.Close(); } catch (Exception) { } return(true); } } // Reset expexted message length mLen = 0; } return(false); }
// Password-Based Key Derivation Function 2. Used to generate "pseudorandom" keys from a given password and salt using a certain PRF applied a certain amount of times (iterations). // dklen specified the "derived key length" in bytes. It is recommended to use a high number for the iterations variable (somewhere around 4096 is the standard for SHA1 currently) public static byte[] PBKDF2(PRF function, byte[] password, byte[] salt, int iterations, int dklen) { byte[] dk = new byte[0]; // Create a placeholder for the derived key uint iter = 1; // Track the iterations while (dk.Length < dklen) { // F-function // The F-function (PRF) takes the amount of iterations performed in the opposite endianness format from what C# uses, so we have to swap the endianness byte[] u = function(password, Support.Concatenate(salt, Support.WriteToArray(new byte[4], Support.SwapEndian(iter), 0))); byte[] ures = new byte[u.Length]; Array.Copy(u, ures, u.Length); for (int i = 1; i < iterations; ++i) { // Iteratively apply the PRF u = function(password, u); for (int j = 0; j < u.Length; ++j) { ures[j] ^= u[j]; } } // Concatenate the result to the dk dk = Support.Concatenate(dk, ures); ++iter; } // Clip aby bytes past what we needed (yes, that's really what the standard is) return(dk.ToLength(dklen)); }
public static byte[] SHA1(byte[] message) { // Initialize buffers uint h0 = 0x67452301; uint h1 = 0xEFCDAB89; uint h2 = 0x98BADCFE; uint h3 = 0x10325476; uint h4 = 0xC3D2E1F0; // Pad message int ml = message.Length + 1; byte[] msg = new byte[ml + ((960 - (ml * 8 % 512)) % 512) / 8 + 8]; Array.Copy(message, msg, message.Length); msg[message.Length] = 0x80; long len = message.Length * 8; for (int i = 0; i < 8; ++i) { msg[msg.Length - 1 - i] = (byte)((len >> (i * 8)) & 255); } //Support.WriteToArray(msg, message.Length * 8, msg.Length - 8); //for (int i = 0; i <4; ++i) msg[msg.Length - 5 - i] = (byte)(((message.Length*8) >> (i * 8)) & 255); int chunks = msg.Length / 64; // Perform hashing for each 512-bit block for (int i = 0; i < chunks; ++i) { // Split block into words uint[] w = new uint[80]; for (int j = 0; j < 16; ++j) { w[j] |= (uint)((msg[i * 64 + j * 4] << 24) | (msg[i * 64 + j * 4 + 1] << 16) | (msg[i * 64 + j * 4 + 2] << 8) | (msg[i * 64 + j * 4 + 3] << 0)); } // Expand words for (int j = 16; j < 80; ++j) { w[j] = Rot(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); } // Initialize chunk-hash uint a = h0, b = h1, c = h2, d = h3, e = h4; // Do hash rounds for (int t = 0; t < 80; ++t) { uint tmp = Rot(a, 5) + func(t, b, c, d) + e + K(t) + w[t]; e = d; d = c; c = Rot(b, 30); b = a; a = tmp; } h0 += a; h1 += b; h2 += c; h3 += d; h4 += e; } return(Support.WriteContiguous(new byte[20], 0, Support.SwapEndian(h0), Support.SwapEndian(h1), Support.SwapEndian(h2), Support.SwapEndian(h3), Support.SwapEndian(h4))); }