Date: Mon, 17 Aug 1998 13:53:10 -0700 (PDT)
From: Roni Korenshtein <ronikoren@yahoo.com>
Subject: JDK's Security API recommendations
To: java-security@java.Sun.COM
Hi Jan,
Thanks for spending the time to meet with us on Friday.
Part of our discussion was related to signatures and I kept thinking
about this after the meeting and I feel I may have not done a good job
articulating my thoughts about this issue during the meeting, mostly
because some of them came to my mind after the meeting. The
opinion/ideas
do not represent Certicom's in any way. As a individual user of the JDK
I'd like to say that I think you guys did a great job in the JDK
and I really enjoy using it. I always say that your use of design
patterns
is excellent and programming to the JDK forces even a novice
programmer to write
better code.
I'm writing this email because to point your attention to a couple of
areas that
could be made more useful (especially if one wants to implement
OpenPGP)
and more in the spirit of OO.
I'm CC'ing Jon Callas who is the main person behind the OpenPGP
standard (as far as
I know) because I think he may be interested in some aspects of this
that are
related to his work.
I'm convinced that the signatures in the JDK (and MessageDigest) have
"not been given all that they deserve" and if you can remedy this, the
JDK would
be a better and more consistent platform.
This email describes how the Signature framework should be modified,
it contains
some code that shows the new usage, and then it shows why the current
API
is deficient from the perspective of OpenPGP.
The main realization I had a few minutes after our meeting is that
signature
(and MessageDigest, and eventually Certificate) should be completely
analogous
to a key in the JDK, and should have a framework of classes and
concepts
(opaque vs. transparent) associated with it, as there is for keys.
Mainly, there should be a "ThingGenerator" , a "Thing", a "ThingSpec",
and a "ThingFactory".
There should be at least the following classes related to signatures:
1. A signature algorithm... currently called Signature, but perhaps
should
be renamed SignatureGenerator...
2. A signature interface, an instance of which is returned by the
sign() method
instead of byte[], analogous to Key, and in fact should implement
the same
interface as java.security.Key, i.e:
getEncoded(), getFormat() & getAlgorithm() are all needed.
3. A SignatureSpec, DSASignatureSpec, etc'
for example, class DSASignatureSpec would contain getR() & getS()
4. A SignatureFactory is needed, to convert opaque signatures to
signature specifications
and vice versa.
all of the above are ver important to support signature transport. The
OpenPGP standard,
for example, specifies how signatures should be externalized to a file
(for transportation).
The format calls for saving the signature (for DSA signature) as Multi
Precision Integer r,
followed by Multi Precision Integer s. Currently the resultant
signature byte array returned
by the Signature algorithms are opaque and very provider-dependent.
There is no guarantee
that a signature byte array returned from a sign method of one
provider can be used
successfully by verify method of another provider, even for the same
signature algorithm.
The "How to write a provider" does not specify anything about the
content or format of this
byte array.
What I mean by that is each provider is free to return any signature
byte array
as long as the same byte array results in successful verification by
the same provider
for the same algorithm. So one provider may attach a version number,
or any other info
to the signature byte array, as long as they know to strip it off when
verifying, this
'signature' would work fine, but only for that provider.
I would like to be able to write code similar to this:
//obtain a signature engine and sign the data
SignatureGenerator signAlgo = SignatureGenerator.getInstance(
algoName);
signAlgo.update( dataToBeSigned);
Signature resultantSignature = signAlgo.sign();
//verify the data
boolean ok = signAlgo.verify( resultantSignature);
//extract information from the opaque signature:
byte[] result = resultantSignature.getEncoded(); //obtain the byte[]
that currently Signature.sign() returns
//would be nice and could be more efficient if this could be done
MessageDigest md = resultantSignature.getMessageDigest();
//where the current MessageDigest is renamed MessageDigestGenerator
byte[] msgDigestBytes = md.getEncoded(); //returns what the
current MessageDigest.digest() retuens
String MsgDigestAlgorithm = md.getAlgorithm();
//convert the signature to transparent signature and extract more
information:
SignatureFactory signatureFactory = resultantSignature.getInstance(
algoName);
DSASignatureSpec signSpec = signatureFactory.getSignatureSpec(
resultantSignature, DSASignatureSpec);
BigInteger R = signSpec.getR();
BigInteger S = signSpec.getS();
As shown in the code above, the signature interface described above in
(2) could also have a
byte[] getHashValue() (or better yet, MessageDigest
getMessageDigest() )
which would return the intermediate hash value. Since all Signatures
have to calculate it
they may as well save it for the purpose of:
1. verify() can check this value during the signature verification
process which should speed up
the process
2. some transport standards may require this value. OpenPGP for
example requires the intermediate
hash value to be transported as part of the signature packet.
Another way of looking at it is from the perspective of OpenPGP:
If you want to implement OpenPGP using the current JDK you are faced
with the following problems:
1. OpenPGP signature needs to be written out as a standard transparent
entity. For DSA for example
the OpenPGP format requires writing out 2 multi-precision integers
r and s.
the JDK does not currently support the concept of a transparent
signature, and therefore
there is no guaranteed way to obtain the transparent values from a
signature.
2. OpenPGP views the signing process as a 2 step operation:
calculation of the Digest, followed
by the encryption of the digest. It therefore requires the result
of the 1st operation, the
resultant msg digest to be written out, and it describes the
verification process as also
a two step operation in which the msg digest is verified first,
followed by the decryption.
The JDK encapsulates and hides the calculation of the message
digest in the sign/verify process.
Therefore, an implementor of OpenPGP will find the Signature class
useless since the implementor
would have to use the low level primitives - MessageDigest and
encryption/decryption to calculate
and verify a signature, in order to have a hold of the intermediate
msg digest result.
3. OpenPGP requires the algorithm type of the message digest result of
the signature to be
written out as well. Currently, in the JDK there is no way to
obtain the Msg digest algorithm
that was used in the calculation of the signature. If you add
getMsgDigestAlgorithm() to
the Signature/Algorithm class it will solve that problem, but the
ideal and most solution
would be to rename the current MessageDigest to what it reall is
MessageDigestGenerator,
and instances of the new MessageDigest would implement an interface
similar to the one the
Key interface defines. this way, the implementor can obtain the
MessageDigest from the signature
and then obtain the algorithm that was used to calculate it by
calling getAlgorithm().
Of course, eventually Certificate should also have the same framework,
consisting of
a CertificateGenerator, Certificate, and CertificateSpec, and then the
security API would be
more usable and consistent.
Thanks,
Roni Korenshtein
_________________________________________________________
DO YOU YAHOO!?
Get your free @yahoo.com address at http://mail.yahoo.com