Re: Fw: My opinions on Key, KeySpec, KeyFactory, KeyGenerator, et. al.

George Chung (gchung@openhorizon.com)
Fri, 13 Mar 1998 20:08:30 -0800

From: "George Chung" <gchung@openhorizon.com>
To: "Jan Luehe" <Jan.Luehe@Eng>, <java-security@javasoft.com>
Subject: Re: Fw: My opinions on Key, KeySpec, KeyFactory, KeyGenerator, et. al.
Date: Fri, 13 Mar 1998 20:08:30 -0800

Jan,
First of all thanks for your time in helping me understand this. I promise
this is my last email on this! :-)

>In the case of a secret key that can be represented as a byte array,
>you're right: The encoding of the key corresponds to the key spec,
>it's simply the byte array.
>
>In all other cases, the encoding is different from the key spec.
>For example, in the case of a DSA public key, the encoding is
>a byte array representing an ASN.1 encoded SEQUENCE of the public value
>y, the prime p, the sub-prime q, and the base g.

Hypothetically, couldn't I just define an encoding "Serialized
DSAPublicKeySpec" and have the byte array be the serialized
DSAPublicKeySpec? That would be legal and at the same time it be almost
exactly the same as having Key be able to return a KeySpec.

<snip>
>The following is an example of how to use a SecretKeyFactory to
>convert secret key data into a SecretKey object, which can be used
>for a subsequent Cipher operation:
>
> byte[] desKeyData = { (byte)0x01, (byte)0x02, ...};
> DESKeySpec desKeySpec = new DESKeySpec(desKeyData);
> SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
> SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
>
>In this case, the underlying implementation of secretKey is based on
>the provider of keyFactory.

I'm just wondering why implementors of Cipher can't do the equivalent of
what the SecretKeyFactory does in the above example inside its
implementation of init(), but perhaps the answer is further below...

>An alternative, provider-independent way of creating a
>functionally equivalent SecretKey object from the same key material
>is to use the SecretKeySpec class, which implements the
>javax.crypto.SecretKey interface:
>
> byte[] desKeyData = { (byte)0x01, (byte)0x02, ...};
> SecretKeySpec secretKey = new SecretKeySpec(desKeyData, "DES");
>[...]
>
>
>This should make you happy. :-)

It definitely does!

>> Now if we consider the encoding/format equivalent in concept to the
KeySpec
>
>Only for secret keys!

With {DSA/RSA}Public/PrivateKey, they are _conceptually_ equivalent in that
a provider knows how to create his opaque key from either. With the
encoding/format, he uses some internal routine. With the KeySpec, he uses
his KeyFactory. Again, if I define my encoding for a DSAPublicKey called
"Serialized DSAPublicKeySpec", then they are almost EXACTLY equivalent.

<snip>
>> Again, what's the difference in the amount of work that a Key provider
has
>> to do whether it:
>> a) supports an interface that requires it to return a vendor _neutral_
>> encoding format
>> b) supports an interface that requires it to return a vendor _neutral_
>> KeySpec
>
>As a provider, you are not required to support any key specs
>other than EncodedKeySpec (to which I am going to add a byte[]
>constructor),
>if you provide a complete feature list to your users, i.e., users who use
>your provider do not have to use any other providers.

OK, I see this class in JDK 1.2 java.security.spec package. So basically,
Key extends EncodedKeySpec, right? I think I'm experiencing an epiphany now.
Hey, if this were made explicit in the interface definition for Key, then
the penny might have dropped a little sooner for me! Oh well, no harm done,
learning is half the fun. So the upshot is that the encoded form is one
instance of a KeySpec!! :-)

Explains much.

>The algorithm-specific key specs are defined so that keys from
>one provider can be used with a different provider, provided that both
>providers supply conversion routines from their keys to the key specs,
>and vice versa.
>
>If your provider does not support any of the algorithm-specific
>key specs (this would be the case if your provider supplied some
>proprietary algorithms), it may still support a complete life-cycle
>for its keys:
>
>1. Key(Pair)Generator returns opaque key objects, which you can use with
>the provider's implementations of the crypto services.
>2. If you want to store your keys for later usage, you call the
>key's getEncoded() method, which returns some kind of encoding for the
>key, which may or may not be standards-based.
>3. If you want to reuse your keys, you wrap their encoding into
>an EncodedKeySpec, and pass that to your provider's key factory,
>which will know how to parse the encoding.

The light is starting to shine...

<snip>
>> Therefore, they should not be exposed to the programmer and should only
be
>> dealt with inside the Cipher implementation.
>
>If my implementation of keys is hardware-based, and my private key
>never leaves the token device, how do you expect me to construct a
>DSAPrivateKeySpec, which expects as one of its parameters the
>private key?

That begs the question: how do I pass that private key into
Signature.initSign()?

There has to be _some_ Java wrapper for that hardward based key, right? Let
me naively think out loud the following...

The Java class HardwareDSAPrivateKey wraps the hardward-based private key
and knows how to return the encoded format. Why can't the Java class
HardwareDSAPrivateKey support getKeySpec() in the same way it supports
getEncoded()? In other words, Key today extends EncodedKeySpec. In the
future, we could imagine that it also supports a getKeySpec() in which it
returns an algorithm specific KeySpec.

DSAPrivateKey.getKeySpec() could return DSAPrivateKeySpec() and thus act as
its own KeyFactory to generate KeySpecs.

The class heirarchy to support this would be Key extends ExtendedKeySpec and
the half of KeyFactory that returns a KeySpec.

In order to support the other half of KeyFactory (converting KeySpec to
Key), Key could support a getInstance(KeySpec, provider).

Just thinking out loud.

<snip>
>Only when you're switching from one provider to another you have to do
>the conversion.
>If one of the providers is hardware based, you may not even be able
>to do the conversion.

My argument is that there must be some layer of Java code that returns the
encoded form of the hardware based key as a byte array. Couldn't that Java
code can simply be augmented to return the algorithm specific KeySpec
through a getKeySpec() method.

Sorry for the marathon exchange. Your previous email answered a lot of
questions, and I should be able to proceed quite nicely. The only minor nit
that I have left is that I _think_ (I'm not sure) that KeyFactory could be
mushed into Key via adding a getKeySpec() and a getInstance() to the
interface and changing it to an abstract base class ala MessageDigest, et.
al. But perhaps my understanding of hardward based keys is too primitive to
fully appreciated the existing class heirarchy.

Best Regards,
George Chung
Open Horizon, Inc.