On Nov 5, 2010, at 12:27 AM, Les Hazlewood wrote:
>> I agree that PasswordManager would not be an ideal name, it's vague.
>> However, HashManager and EncryptionManager reflect the one-way and two-way
>> functions. I would be worried that we would be mixing concerns in a
>> CredentialsManager. I am making my comments with my previous outline in
>> mind. It might be useful if you provided bits of code to give a bit more
>> context.
>
> In attempting to put together an example, I think I found where there
> might be a mental disconnect. Let's see if I can ask some more
> questions that help me understand your use case.
>
> What are the K (key) and PD (perData) values and why would they be
> necessary? I don't understand their purpose at the moment.
I think the problem here is my use of the word key which is pregnant with many
meanings here. For my use case key is simply an index that is used to lookup
the information that was used to obtain the hash or encryption. Let me make my
outline more concrete.
class MyHash extends Hash<String>
{
}
class MySaltyHasher implements Hasher<String, Long> {
private final String myKey;
private final int numHashes;
private final String algorithm;
public MySaltyHasher(String myKey, String algorithm, int numHashes) {
this.myKey = myKey; this.algorithm = algorithm; this.numHashes = numHashes; }
public MyHash hash(byte[] data, Long salt)
{
MyHash myHash = new MyHash();
myHash.key = myKey;
myHash.hash = doHash(data, salt);
return myHash;
}
...
}
class MyHashManager implements HashManager<String, Long, MySaltyHasher> extends
Map<String, MySaltyHasher > {
public MyHash hash(String key, byte[] data, Long salt);
}
So, the first thing that happens is some security guy decides that the company
needs 2 iterations of hashing to make things safe. So, he registers
myHashManager.add("d3poq84f98", new MySaltyHasher("d3poq84f98", "SHA1", 2));
d3poq84f98 is the new official index.
When a website needs a secure hash it knows that "d3poq84f98" is the current
index.
MyHash myHash = myHashManager("d3poq84f98", data, salt);
Here the salt is the usual per data salt. Where it gets stored is up to the
website implementation.
The index "d3poq84f98" is associated with the hash. We use the index
"d3poq84f98" so as don't leak information about what algorithm or how many
iterations were used. So it's safe for the tuple ("d3poq84f98", hashdata) to
go out into the wild.
Let's say that someone comes back six days later with that tuple. We have
enough information to regenerate the hash. If we feel that 2 iterations is not
enough we can register a new hasher.
myHashManager.add("xweff932hbf", new MySaltyHasher("xweff932hbf", "MD5",
1024));
xweff932hbf is the new official index. We can keep both around or we can
remove the old one. It depends on what semantics the security guy wants.
Let's say we delete the old one.
If someone comes back to us with the old "d3poq84f98" tuple. We know then that
the hash is invalid and we can take the appropriate course of action.
So, to recap the index is a way of associating what was used to generate a hash
without divulging that information to outsides. It's also a helpful when
hashes are long lived.
A similar example can be constructed for encryption.
> The information used for Shiro to reconstitute the hash, such as # of
> hash iterations is usually application wide and can be specified as a
> configuration parameter in Shiro (e.g.
> credentialsManager.numHashIterations = 2048). The only reason I can
> see for storing it in the salt directly is that you might want the #
> of hash iterations to be unique per user. Is this what you'd like to
> support?
>
> While this is possible, most applications that would ever change that
> number end up doing it on a periodic basis system-wide, for example,
> once a week or once a month for all accounts. I'm not sure if
> per-user values would be 'worth it', but I'm totally open on this and
> would love to see what you guys think.
I have run into situations where the hashers needed to be updated and we were
in trouble because we did not associate any additional information with the
hashes/encryptions. I need to support it and it would be nice if Shiro made it
easier for me to do so.
>>> Also, we already have Hash and CipherService concepts in Shiro (no
>>> need for something like Encryptor that I can see) - the
>>
>> Can you explain your statement "no need for something like Encryptor that I
>> can see"?
>
> To me, Encryptor looked like the same thing as the CipherService in
> practice. Is this not the case?
Ahh, ok. You meant the class itself. I agree to some extent so long as I get
the same results as above. Please keep in mind that the above is just a sketch
to get my ideas across. They are meant as a basis for discussion.
>>> CredentialsManager would just sit a level above these and use them
>>> both, probably along with a RandomNumberGenerator and tie all three
>>> things together.
>>
>> Again, a bit more code would help here. :)
>
> For example,
>
> public interface HashedCredentialsManager {
> HashedCredentials hashCredentials(ByteSource credentials);
> boolean credentialsMatch(AuthenticationToken token,
> AuthenticationInfo info);
> }
>
> public interface HashedCredentials {
> Hash getCredentials();
> ByteSource getSalt();
> }
>
> An implementation of this interface would simply use delegation - it
> would would use an instance of RandomNumberGenerator to acquire a
> salt, pair it with the credentials as the key, hash it using the
> configured hash algorithm name, and return a HashedCredentials
> instance.
>
> The HashedCredentials instance would only be used so the caller could
> acquire both the generated (hashed) credentials/password as well as
> the salt so they can store both as necessary.
>
> The 'credentialsMatch' method would just delegate to an internal
> HashedCredentialsMatcher using the same hash algorithm.
>
> Also note that the number of hash iterations doesn't need to be
> 'known' to anything except the HashedCredentialsManager
> implementation, allowing for a single place for configuration.
>
> But this begs the question - the above HashedCredentialsManager _is_ a
> HashedCredentialsMatcher by the presence of the 'credentialsMatch'
> method. Wouldn't it make more sense to just have
> HashedCredentialsManager sub-interface CredentialsMatcher?
It seems to me that you are talking about higher level objects that would be
used by the "casual" user. My classes would be the lower level machinery that
would make it happen and could be used in other situations where a simple login
was not the use case.
>>> Finally, it doesn't make sense to me to have a 'key' attribute forced
>>> upon a Hash interface. Hashes have no concept of a 'key' and that
>>
>> The key is critical since it is used to indicate what hash or encryption was
>> used to obtain that bit of data.
>
> Please see above. I'm assuming we're talking about credentials
> matching still and not PBE or MACs.
>
> Anyway, this is great discussion - I hope our mental models sync up :)
Yeah, as I mentioned above, the word key was a poor choice. Index may be
better.
Regards,
Alan