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); }
public static byte[] HashBytes(byte[] bytes, HashIdentifier hashAlgorithm) { HashAlgorithm hash; if (hashAlgorithm == HashIdentifier.SHA512) { hash = SHA512.Create(); } else if (hashAlgorithm == HashIdentifier.SHA384) { hash = SHA384.Create(); } else if (hashAlgorithm == HashIdentifier.SHA256) { hash = SHA256.Create(); } else if (hashAlgorithm == HashIdentifier.SHA1) { hash = SHA1.Create(); } else if (hashAlgorithm == HashIdentifier.MD5) { hash = MD5.Create(); } else { throw new InvalidOperationException("Unsupported hash algorithm"); } using (hash) { return(hash.ComputeHash(bytes)); } }
public static byte[] HashBytes(byte[] bytes, HashIdentifier hashAlgorithm) { using (HashAlgorithm hash = Create(hashAlgorithm)) { return(hash.ComputeHash(bytes)); } }
private static byte[] DeriveKey(byte[] hashValue, HashIdentifier 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 = CryptoHelpers.HashBytes(derivedKey, hashAlgorithm); 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 = CryptoHelpers.HashBytes(derivedKey, hashAlgorithm); return(CryptoHelpers.Combine(x1, x2)); }
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 HashAlgorithm Create(HashIdentifier hashAlgorithm) { switch (hashAlgorithm) { case HashIdentifier.SHA512: return(SHA512.Create()); case HashIdentifier.SHA384: return(SHA384.Create()); case HashIdentifier.SHA256: return(SHA256.Create()); case HashIdentifier.SHA1: return(SHA1.Create()); case HashIdentifier.MD5: return(MD5.Create()); default: throw new InvalidOperationException("Unsupported hash algorithm"); } }
/// <summary> /// 2.3.4.7 ECMA-376 Document Encryption Key Generation (Standard Encryption) /// </summary> private static byte[] GenerateEcma376SecretKey(string password, byte[] saltValue, HashIdentifier hashIdentifier, int keySize, int verifierHashSize) { byte[] hash; using (var hashAlgorithm = CryptoHelpers.Create(hashIdentifier)) { hash = hashAlgorithm.ComputeHash(CryptoHelpers.Combine(saltValue, System.Text.Encoding.Unicode.GetBytes(password))); for (int i = 0; i < 50000; i++) { hash = hashAlgorithm.ComputeHash(CryptoHelpers.Combine(BitConverter.GetBytes(i), hash)); } hash = hashAlgorithm.ComputeHash(CryptoHelpers.Combine(hash, BitConverter.GetBytes(0))); // The algorithm in this 'DeriveKey' function is the bit that's not clear from the documentation hash = DeriveKey(hash, hashAlgorithm, keySize, verifierHashSize); } Array.Resize(ref hash, keySize / 8); return(hash); }
/// <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 void TestHashDetection(string hash, bool accepted) { var hashed = HashIdentifier.GetHashAlgorithm(hash); accepted.Should().Be(hashed != null); }
private BlobIdentifier CreateBlobIdentifier() { const string HashIdentifier = "54CE418A2A89A74B42CC39630167795DED5F3B16A75FF32A01B2B01C59697784"; return(BlobIdentifier.CreateFromAlgorithmResult(HashIdentifier.ToUpperInvariant())); }