On 9/6/2018 9:53 AM, Adam Petcher wrote:
On 9/5/2018 5:53 PM, Michael StJohns wrote:
BigInteger is not required to encode a PKCS8 key, but its trivial to
translate from BigInteger to PKCS8 and vice versa. Note that
internally, the current BigInteger stores the magnitude as an array
of int in big endian order and stores the sign separately. The
BigInteger (int sigNum, byte[] magnitude) constructor mostly just
copies the magnitude bytes over (and converts 4 bytes to an integer)
for positive integers. While the current BigInteger doesn't have a
byte[] BigInteger.getMagnitude() call, it would be trivial to
subclass BigInteger to copy the magnitude bytes (without branching) out.
In any event, for NewEC to OldEc - you do use the sign/magnitude call
to create the BigInteger - no leaking on the part of NewEC, and once
it gets to OldEC its not your problem. For OldEc to NewEc you copy
the BigInteger to NewBigInteger (trivial wrapper class) and do a
getMagnitude().
See the code for BigInteger[1]. The sign/magnitude constructor calls
stripLeadingZeroBytes (line 405) on the magnitude to convert it to an
int array. This method compares the leading values in the byte array
to zero in a short-circuit expression in a for loop (line 4298). So
this constructor branches on the value that is supplied to it, and it
cannot be used in a branchless implementation.
I don't know how to write this branchless getMagnitude method that you
are proposing. I would need to convert from a variable-length int
array to a fixed-length byte array. In doing this, I can't branch on
the length of the variable-length array, because doing so would leak
whether the high-order bits of the key are zero. If you know how to do
this, then please provide some code to illustrate how it is done.
Simple way to do this is to extend BigInteger and fix these perceived
problems. You may have to replace/replicate pretty much everything, but
as long as it has a BigInteger signature when output, you're good to
go. Actually, do that - clone BigInteger.java as SafeBigInteger.java,
have extend java.math.BigInteger and change out the things that bother
you. I checked - BigInteger is not a final class so this should work.
E.g. as long as *I* can call the functions I need to call on the
object you exported, I'm fine with it.
In any event, you're still missing the point here. You're EXPORTING the
key from your provider to other providers which probably already don't
care that much about the one in 256 (approx - slightly larger) time
where exporting the key might leak the fact of leading zero bits.
[1]
http://hg.openjdk.java.net/jdk/jdk/file/805807f15830/src/java.base/share/classes/java/math/BigInteger.java
While the contract for getEncoded() explicitly allows for a null
result, getS() of ECPrivateKey does not. This more than any other
reason appears to be why the PKCS 11 provider represents the
ECPrivateKey as a simple PrivateKey object.
Good point. There is no need for the private keys for this provider to
implement ECPrivateKey, since there is only one method that is
effectively unimplemented. We should use a new implementation class
(not ECPrivateKeyImpl) that implements PrivateKey, not ECPrivateKey.
*pounds head on table* Sure. And then you can't use any translation
features and then you break all the code.
So implementing your provider requires other providers to change?
Because? Do you expect BouncyCastle and NSS to change as well?
I think the situation is improved by not having the new private keys
implement ECPrivateKey. Then the JDK ECKeyFactory code does not need
to change, and neither do other providers, assuming they behave in a
similar way. Though I think it is acceptable if other providers don't
behave this way, and therefore cannot translate private keys from this
new provider. I've updated the JEP to indicate that interoperability
with these providers is a non-goal.
OK. At this point you're no longer calling this an EC key. Make sure
you catch all the places where ECPrivateKey is used instead of
PrivateKey. I think you're incredibly short sighted and not a lot of
folks will implement this, but go for it. I think its a *really* bad
idea and that you're fixing the wrong problems.
The only way to get private keys in or out of the new provider is
through a PKCS#8 encoding. Moving keys to/from another provider that
supports ECPrivateKeySpec but not PKCS#8 encoding can be
accomplished by translating the specs---possibly with the help of a
KeyFactory that supports both, like the one in SunEC.
*pounds head against table* Bits are bits are bits. Creating a
PKCS8EncodedKeySpec gets you a byte array which you can convert to a
BigInteger by decoding the PKCS8 structure and taking the PKCS8
PrivateKey octets and doing new BigInteger (1, privateKeyOctets).
That doesn't require ASN1 integer representation (e.g. leading byte
is zero if high bit is set) and doesn't cause a branch.
See above for my explanation of why this solution does, in fact, branch.
See my commentary on why this still doesn't matter.
Later, Mike