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

Reply via email to