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.
[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.
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.
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.