/// <summary> /// Generates a seed, in accordance with RFC 7292, §B.2 /// </summary> /// <param name="H">Hash function</param> /// <param name="r">Iteration count</param> /// <param name="P">Formatted password.</param> /// <param name="S">Salt.</param> /// <param name="n">Number of pseudo-random bits to generate.</param> /// <param name="ID">Purpose of key: /// /// If ID=1, then the pseudorandom bits being produced are to be used /// as key material for performing encryption or decryption. /// /// 2. If ID=2, then the pseudorandom bits being produced are to be used /// as an IV (Initial Value) for encryption or decryption. /// /// 3. If ID=3, then the pseudorandom bits being produced are to be used /// as an integrity key for MACing. /// </param> internal static byte[] PRF(HashFunction H, int r, byte[] P, byte[] S, int n, byte ID) { int u, v; if ((n & 7) != 0) { throw new ArgumentException("Must be a factor of 8.", nameof(n)); } switch (H) { case HashFunction.MD5: u = 128; v = 512; break; case HashFunction.SHA1: u = 160; v = 512; break; case HashFunction.SHA256: u = 256; v = 512; break; case HashFunction.SHA384: u = 384; v = 1024; break; case HashFunction.SHA512: u = 512; v = 1024; break; default: throw new ArgumentException("Hash function not supported.", nameof(H)); } int v8 = v / 8; int u8 = u / 8; byte[] D = new byte[v8]; int i, j, c; for (i = 0; i < v8; i++) { D[i] = ID; } S = Extend(S, v); P = Extend(P, v); byte[] I = Primitives.CONCAT(S, P); int i8 = I.Length; c = (n + u - 1) / u; byte[][] As = new byte[c][]; for (i = 0; i < c; i++) { As[i] = Primitives.CONCAT(D, I); for (j = 0; j < r; j++) { As[i] = Hashes.ComputeHash(H, As[i]); } byte[] B = Extend(As[i], v); for (j = 0; j < i8; j += v8) { AddTo(I, j, B, true); } } byte[] A = Primitives.CONCAT(As); if (A.Length != n) { Array.Resize <byte>(ref A, n); } return(A); }
/// <summary> /// Formats a password, in accordance with RFC 7292, §B.1. /// </summary> /// <param name="Password">Password</param> /// <returns>Formatted password</returns> internal static byte[] FormatPassword(string Password) { return(Primitives.CONCAT(Encoding.BigEndianUnicode.GetBytes(Password), new byte[] { 0, 0 })); }