public override bool VerifyPassword(string password) { var secretKey = HashPassword(password, PasswordSaltValue, PasswordHashAlgorithm, PasswordSpinCount); var inputBlockKey = CryptoHelpers.HashBytes( CryptoHelpers.Combine(secretKey, new byte[] { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 }), PasswordHashAlgorithm); Array.Resize(ref inputBlockKey, PasswordKeyBits / 8); var valueBlockKey = CryptoHelpers.HashBytes( CryptoHelpers.Combine(secretKey, new byte[] { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e }), PasswordHashAlgorithm); Array.Resize(ref valueBlockKey, PasswordKeyBits / 8); using (var cipher = CryptoHelpers.CreateCipher(PasswordCipherAlgorithm, PasswordKeyBits, PasswordBlockSize * 8, PasswordCipherChaining)) { var decryptedVerifier = CryptoHelpers.DecryptBytes(cipher, PasswordEncryptedVerifierHashInput, inputBlockKey, PasswordSaltValue); var decryptedVerifierHash = CryptoHelpers.DecryptBytes(cipher, PasswordEncryptedVerifierHashValue, valueBlockKey, PasswordSaltValue); var verifierHash = CryptoHelpers.HashBytes(decryptedVerifier, PasswordHashAlgorithm); for (var i = 0; i < Math.Min(decryptedVerifierHash.Length, verifierHash.Length); ++i) { if (decryptedVerifierHash[i] != verifierHash[i]) { return(false); } } return(true); } }
private static byte[] DeriveKey(byte[] hashValue, HashAlgorithm hashAlgorithm, int keySize, int verifierHashSize) { // And one more hash to derive the key byte[] derivedKey = new byte[64]; // This is step 4a in 2.3.4.7 of MS_OFFCRYPT version 1.0 // and is required even though the notes say it should be // used only when the encryption algorithm key > hash length. for (int i = 0; i < derivedKey.Length; i++) { derivedKey[i] = (byte)(i < hashValue.Length ? 0x36 ^ hashValue[i] : 0x36); } byte[] x1 = hashAlgorithm.ComputeHash(derivedKey); if (verifierHashSize > keySize / 8) { return(x1); } for (int i = 0; i < derivedKey.Length; i++) { derivedKey[i] = (byte)(i < hashValue.Length ? 0x5C ^ hashValue[i] : 0x5C); } byte[] x2 = hashAlgorithm.ComputeHash(derivedKey); return(CryptoHelpers.Combine(x1, x2)); }
public override byte[] GenerateBlockKey(int blockNumber, byte[] secretKey) { var salt = CryptoHelpers.HashBytes(CryptoHelpers.Combine(secretKey, BitConverter.GetBytes(blockNumber)), HashAlgorithm); Array.Resize(ref salt, BlockSize); return(salt); }
private static byte[] GenerateSecretKey(string password, byte[] saltValue, HashIdentifier hashIdentifier, byte[] encryptedKeyValue, int spinCount, int keyBits, SymmetricAlgorithm cipher) { var block3 = new byte[] { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 }; byte[] hash; using (var hashAlgorithm = CryptoHelpers.Create(hashIdentifier)) { hash = HashPassword(password, saltValue, hashAlgorithm, spinCount); hash = CryptoHelpers.HashBytes(CryptoHelpers.Combine(hash, block3), hashIdentifier); } // Truncate or pad with 0x36 var hashSize = hash.Length; Array.Resize(ref hash, keyBits / 8); for (var i = hashSize; i < keyBits / 8; i++) { hash[i] = 0x36; } // NOTE: the stored salt is padded to a multiple of the block size which affects AES-192 var decryptedKeyValue = CryptoHelpers.DecryptBytes(cipher, encryptedKeyValue, hash, saltValue); Array.Resize(ref decryptedKeyValue, keyBits / 8); return(decryptedKeyValue); }
private static byte[] HashPassword(string password, byte[] saltValue, HashIdentifier hashAlgorithm, int spinCount) { var h = CryptoHelpers.HashBytes(CryptoHelpers.Combine(saltValue, System.Text.Encoding.Unicode.GetBytes(password)), hashAlgorithm); for (var i = 0; i < spinCount; i++) { h = CryptoHelpers.HashBytes(CryptoHelpers.Combine(BitConverter.GetBytes(i), h), hashAlgorithm); } return(h); }
public static byte[] GenerateSecretKey(string password, byte[] salt) { if (password.Length > 16) { password = password.Substring(0, 16); } var h = CryptoHelpers.HashBytes(System.Text.Encoding.Unicode.GetBytes(password), HashIdentifier.MD5); Array.Resize(ref h, 5); // Combine h + salt 16 times: h = CryptoHelpers.Combine(h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt, h, salt); h = CryptoHelpers.HashBytes(h, HashIdentifier.MD5); Array.Resize(ref h, 5); return(h); }
internal static ushort CreatePasswordVerifier_Method1(byte[] passwordBytes) { var passwordArray = CryptoHelpers.Combine(new byte[] { (byte)passwordBytes.Length }, passwordBytes); ushort verifier = 0x0000; for (var i = 0; i < passwordArray.Length; ++i) { var passwordByte = passwordArray[passwordArray.Length - 1 - i]; ushort intermediate1 = (ushort)(((verifier & 0x4000) == 0) ? 0 : 1); ushort intermediate2 = (ushort)(verifier * 2); intermediate2 &= 0x7FFF; ushort intermediate3 = (ushort)(intermediate1 | intermediate2); verifier = (ushort)(intermediate3 ^ passwordByte); } return((ushort)(verifier ^ 0xCE4B)); }
/// <summary> /// 2.3.4.7 ECMA-376 Document Encryption Key Generation (Standard Encryption) /// </summary> private static byte[] GenerateEcma376SecretKey(string password, byte[] saltValue, HashIdentifier hashAlgorithm, int keySize, int verifierHashSize) { var h = CryptoHelpers.HashBytes(CryptoHelpers.Combine(saltValue, System.Text.Encoding.Unicode.GetBytes(password)), hashAlgorithm); for (int i = 0; i < 50000; i++) { h = CryptoHelpers.HashBytes(CryptoHelpers.Combine(BitConverter.GetBytes(i), h), hashAlgorithm); } h = CryptoHelpers.HashBytes(CryptoHelpers.Combine(h, BitConverter.GetBytes(0)), hashAlgorithm); // The algorithm in this 'DeriveKey' function is the bit that's not clear from the documentation h = DeriveKey(h, hashAlgorithm, keySize, verifierHashSize); Array.Resize(ref h, keySize / 8); return(h); }
public override byte[] GenerateBlockKey(int blockNumber, byte[] secretKey) { if ((Flags & EncryptionHeaderFlags.AES) != 0) { /*var salt = CryptoHelpers.Combine(secretKey, BitConverter.GetBytes(blockNumber)); * salt = CryptoHelpers.HashBytes(salt, HashAlgorithm); * Array.Resize(ref salt, (int)KeySize / 8); * return salt;*/ throw new Exception("Block key for ECMA-376 Standard Encryption not implemented"); } else if ((Flags & EncryptionHeaderFlags.CryptoAPI) != 0) { var salt = CryptoHelpers.Combine(secretKey, BitConverter.GetBytes(blockNumber)); salt = CryptoHelpers.HashBytes(salt, HashAlgorithm); Array.Resize(ref salt, (int)KeySize / 8); return(salt); } else { throw new InvalidOperationException("Unknown encryption type"); } }
/// <summary> /// 2.3.5.2 RC4 CryptoAPI Encryption Key Generation /// </summary> private static byte[] GenerateCryptoApiSecretKey(string password, byte[] saltValue, HashIdentifier hashAlgorithm, int keySize) { return(CryptoHelpers.HashBytes(CryptoHelpers.Combine(saltValue, System.Text.Encoding.Unicode.GetBytes(password)), hashAlgorithm)); }
public override byte[] GenerateBlockKey(int blockNumber, byte[] secretKey) { var salt = CryptoHelpers.Combine(secretKey, BitConverter.GetBytes(blockNumber)); return(CryptoHelpers.HashBytes(salt, HashIdentifier.MD5)); }