The keys are possible with NBT, it would be quite easy to have each key have an integer stored in NBT data, the lock could then have the same NBT integer and a simple if statement could check if they matched and allow the key to open the lock.
As for the dungeon generation, I would look at the generation for villages as they are generated based off the seed and are placed procedurally (Just not infinitely)