public static byte[] WithHeader(byte[] message) { byte[] nmsg = new byte[message.Length + 4]; Support.WriteToArray(nmsg, message.Length, 0); Array.Copy(message, 0, nmsg, 4, message.Length); return(nmsg); }
// 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)); }
// Internal methods for encryption :) private static uint KSchedCore(uint input, int iteration) { input = Rotate(input); byte[] bytes = Support.WriteToArray(new byte[4], input, 0); for (int i = 0; i < bytes.Length; ++i) { bytes[i] = SBox(bytes[i]); } bytes[bytes.Length - 1] ^= RCON(iteration); return((uint)Support.ReadInt(bytes, 0)); }
private static byte[] KeySchedule(byte[] key, BitMode mode) { int n = mode == BitMode.Bit128 ? 16 : mode == BitMode.Bit192 ? 24 : 32; int b = mode == BitMode.Bit128 ? 176 : mode == BitMode.Bit192 ? 208 : 240; byte[] output = new byte[b]; Array.Copy(key, output, n); int rcon_iter = 1; int accruedBytes = n; while (accruedBytes < b) { // Generate 4 new bytes of extended key byte[] t = Support.WriteToArray(new byte[4], KSchedCore((uint)Support.ReadInt(output, accruedBytes - 4), rcon_iter), 0); ++rcon_iter; for (int i = 0; i < 4; ++i) { t[i] ^= output[accruedBytes - n + i]; } Array.Copy(t, 0, output, accruedBytes, 4); accruedBytes += 4; // Generate 12 new bytes of extended key for (int i = 0; i < 3; ++i) { Array.Copy(output, accruedBytes - 4, t, 0, 4); for (int j = 0; j < 4; ++j) { t[j] ^= output[accruedBytes - n + j]; } Array.Copy(t, 0, output, accruedBytes, 4); accruedBytes += 4; } // Special processing for 256-bit key schedule if (mode == BitMode.Bit256) { Array.Copy(output, accruedBytes - 4, t, 0, 4); for (int j = 0; j < 4; ++j) { t[j] = (byte)(SBox(t[j]) ^ output[accruedBytes - n + j]); } Array.Copy(t, 0, output, accruedBytes, 4); accruedBytes += 4; } // Special processing for 192-bit key schedule if (mode != BitMode.Bit128) { for (int i = mode == BitMode.Bit192 ? 1 : 2; i >= 0; --i) { Array.Copy(output, accruedBytes - 4, t, 0, 4); for (int j = 0; j < 4; ++j) { t[j] ^= output[accruedBytes - n + j]; } Array.Copy(t, 0, output, accruedBytes, 4); accruedBytes += 4; } } } return(output); }