Under which conditions would it be OK to use “H(pass||data)”? I understand that the main motivation for HMAC is extension attacks.  If data always has content-length either implicit in the app or even explicitly put into the hash, I get the impression that HMAC is not necessary.  The motivation is to allow password based encryption of keys, using widely available primitives, and periodic rotating of master-password without re-encrypting data (but re-encrypting keys):

file.name = "foo.txt"
file.iv = freshRandom256Bits() 
filekey = freshRandom256Bits() #only master learns this
#encrypted key
file.encryptedKey = sha256(masterpwd+":"+file.iv) ^ filekey
#make it hard to forge data
file.auth = sha256(masterpwd+":"+file.owner+":"+file.encryptedKey)
#write data stream and file meta, then filekey goes out of scope
writeEncryptedIO(file, filekey)


In this case, the encryptedKey has a known length.  In that case, HMAC is not strictly necessary, no?  If I did use an HMAC variant like:

$$h(k || h(k || data))$$

Does it really buy me anything? Is it OK to omit the XOR with constants that are prescribed?  I'm under the impression that the whole reason HMAC is good is that it solves the extension problem by making the thing appended to k be of a known length.
I think the attack by Preneel and van Oorschot (MDx-MAC and Building Fast MACs from Hash Functions, CRYPTO'95) in Proposition 4 applies. It was cited by PulpSpy in reply to my question about H(pass||length(data)||data). With fixed-length data, that amounts to a known suffix for the key.

Proposition 4 states in a nutshell that for a generic construction which generally covers H(…||data||…) where H is an $n$-bit hash function, there is an attack that allows the attacker to replace some trailing blocks. The attack does however require about $2^{n/2}$ known text-MAC pairs, which is not feasible with a 256-bit hash. So this 20-year old result exhibits a theoretical attack. I don't know if there are more recent results that show a more practical attack.