Changeset eff0cac for core/java


Ignore:
Timestamp:
Jul 1, 2018 11:10:06 AM (2 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
a895bcc
Parents:
c65ce1d
Message:

EdDSA: Backport versions 0.2/0.3 from github:

  • Change key encoding to match curdle draft
  • Support key decoding based on curdle draft
  • Implement true constant-time cmov()
  • Add handling of X509Key-wrapped EdDSA keys (GitHub? PR #47)
  • Clarify that KeyPairGenerator? takes a key size, not strength
  • Javadocs

GitHub? PR #58:

  • Make GroupElement? immutable by moving the pre-computed logic to the constructors, allowing the synchronized checking of whether the pre-computed logic had executed or not to be removed since it always has when it is used because those code paths are modified to request it at construction time.
  • This allows getNegativeA() to be lazy, and doesn't need volatile due to the immutability (and final fields - this is important part of the contract with the JVM memory model).
  • Remove synchronized contention from the named curve table get method.
  • Generally remove use of the named curve table get method with a constant curve name in hot code paths in favour of using a new static constant for the curve spec.

Overall performance changes:

  • Keygen 46% faster
  • Signing 39% slower (due to cmov)
  • Verify 2% faster
Location:
core/java
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/crypto/eddsa/EdDSAEngine.java

    rc65ce1d reff0cac  
    1212import java.security.SignatureException;
    1313import java.security.spec.AlgorithmParameterSpec;
     14import java.security.spec.InvalidKeySpecException;
     15import java.security.spec.X509EncodedKeySpec;
    1416import java.util.Arrays;
    1517
     
    5557 */
    5658public final class EdDSAEngine extends Signature {
     59    public static final String SIGNATURE_ALGORITHM = "NONEwithEdDSA";
     60
    5761    private MessageDigest digest;
    5862    private ByteArrayOutputStream baos;
     
    7781
    7882    /**
    79      * No specific hash requested, allows any EdDSA key.
     83     * No specific EdDSA-internal hash requested, allows any EdDSA key.
    8084     */
    8185    public EdDSAEngine() {
    82         super("EdDSA");
    83     }
    84 
    85     /**
    86      * Specific hash requested, only matching keys will be allowed.
     86        super(SIGNATURE_ALGORITHM);
     87    }
     88
     89    /**
     90     * Specific EdDSA-internal hash requested, only matching keys will be allowed.
    8791     * @param digest the hash algorithm that keys must have to sign or verify.
    8892     */
     
    148152            } else if (!key.getParams().getHashAlgorithm().equals(digest.getAlgorithm()))
    149153                throw new InvalidKeyException("Key hash algorithm does not match chosen digest");
     154        } else if (publicKey.getClass().getName().equals("sun.security.x509.X509Key")) {
     155            // X509Certificate will sometimes contain an X509Key rather than the EdDSAPublicKey itself; the contained
     156            // key is valid but needs to be instanced as an EdDSAPublicKey before it can be used.
     157            EdDSAPublicKey parsedPublicKey;
     158            try {
     159                parsedPublicKey = new EdDSAPublicKey(new X509EncodedKeySpec(publicKey.getEncoded()));
     160            } catch (InvalidKeySpecException ex) {
     161                throw new InvalidKeyException("cannot handle X.509 EdDSA public key: " + publicKey.getAlgorithm());
     162            }
     163            engineInitVerify(parsedPublicKey);
    150164        } else {
    151165            throw new InvalidKeyException("cannot identify EdDSA public key: " + publicKey.getClass());
     
    312326     *</pre>
    313327     *
     328     * @param data the message to be signed
     329     * @return the signature
    314330     * @throws SignatureException if update() already called
    315331     * @see #ONE_SHOT_MODE
     
    331347     *</pre>
    332348     *
     349     * @param data byte array containing the message to be signed
     350     * @param off the start of the message inside data
     351     * @param len the length of the message
     352     * @return the signature
    333353     * @throws SignatureException if update() already called
    334354     * @see #ONE_SHOT_MODE
     
    352372     *</pre>
    353373     *
     374     * @param data the message that was signed
     375     * @param signature of the message
     376     * @return true if the signature is valid, false otherwise
    354377     * @throws SignatureException if update() already called
    355378     * @see #ONE_SHOT_MODE
     
    371394     *</pre>
    372395     *
     396     * @param data byte array containing the message that was signed
     397     * @param off the start of the message inside data
     398     * @param len the length of the message
     399     * @param signature of the message
     400     * @return true if the signature is valid, false otherwise
    373401     * @throws SignatureException if update() already called
    374402     * @see #ONE_SHOT_MODE
     
    390418     *</pre>
    391419     *
     420     * @param data the message that was signed
     421     * @param signature byte array containing the signature
     422     * @param sigoff the start of the signature
     423     * @param siglen the length of the signature
     424     * @return true if the signature is valid, false otherwise
    392425     * @throws SignatureException if update() already called
    393426     * @see #ONE_SHOT_MODE
     
    409442     *</pre>
    410443     *
     444     * @param data byte array containing the message that was signed
     445     * @param off the start of the message inside data
     446     * @param len the length of the message
     447     * @param signature byte array containing the signature
     448     * @param sigoff the start of the signature
     449     * @param siglen the length of the signature
     450     * @return true if the signature is valid, false otherwise
    411451     * @throws SignatureException if update() already called
    412452     * @see #ONE_SHOT_MODE
  • core/java/src/net/i2p/crypto/eddsa/EdDSAKey.java

    rc65ce1d reff0cac  
    1212public interface EdDSAKey {
    1313    /**
    14      * return a parameter specification representing the EdDSA domain
    15      * parameters for the key.
     14     * The reported key algorithm for all EdDSA keys
     15     * @since 0.9.36
     16     */
     17    public String KEY_ALGORITHM = "EdDSA";
     18
     19    /**
     20     * @return a parameter specification representing the EdDSA domain
     21     *         parameters for the key.
    1622     */
    1723    public EdDSAParameterSpec getParams();
  • core/java/src/net/i2p/crypto/eddsa/EdDSAPrivateKey.java

    rc65ce1d reff0cac  
    1414 * An EdDSA private key.
    1515 *<p>
    16  * Warning: Private key encoding is not fully specified in the
    17  * current IETF draft. This implementation uses PKCS#8 encoding,
     16 * Warning: Private key encoding is based on the current curdle WG draft,
    1817 * and is subject to change. See getEncoded().
    1918 *</p><p>
    20  * Ref: https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04
     19 * For compatibility with older releases, decoding supports both the old and new
     20 * draft specifications. See decode().
     21 *</p><p>
     22 * Ref: https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
     23 *</p><p>
     24 * Old Ref: https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04
    2125 *</p>
    2226 *
     
    3438    private final EdDSAParameterSpec edDsaSpec;
    3539
     40    // OID 1.3.101.xxx
     41    private static final int OID_OLD = 100;
     42    private static final int OID_ED25519 = 112;
     43    private static final int OID_BYTE = 11;
     44    private static final int IDLEN_BYTE = 6;
     45
    3646    public EdDSAPrivateKey(EdDSAPrivateKeySpec spec) {
    3747        this.seed = spec.getSeed();
     
    4858    public EdDSAPrivateKey(PKCS8EncodedKeySpec spec) throws InvalidKeySpecException {
    4959        this(new EdDSAPrivateKeySpec(decode(spec.getEncoded()),
    50                                      EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512)));
    51     }
    52 
     60                                     EdDSANamedCurveTable.ED_25519_CURVE_SPEC));
     61    }
     62
     63    @Override
    5364    public String getAlgorithm() {
    54         return "EdDSA";
    55     }
    56 
     65        return KEY_ALGORITHM;
     66    }
     67
     68    @Override
    5769    public String getFormat() {
    5870        return "PKCS#8";
     
    6072
    6173    /**
    62      *  This follows the docs from
    63      *  java.security.spec.PKCS8EncodedKeySpec
    64      *  quote:
     74     * Returns the public key in its canonical encoding.
     75     *<p>
     76     * This implements the following specs:
     77     *<ul><li>
     78     * General encoding: https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
     79     *</li><li>
     80     * Key encoding: https://tools.ietf.org/html/rfc8032
     81     *</li></ul>
     82     *<p>
     83     * This encodes the seed. It will return null if constructed from
     84     * a spec which was directly constructed from H, in which case seed is null.
     85     *</p><p>
     86     * For keys in older formats, decoding and then re-encoding is sufficient to
     87     * migrate them to the canonical encoding.
     88     *</p>
     89     * Relevant spec quotes:
    6590     *<pre>
    66      *  The PrivateKeyInfo syntax is defined in the PKCS#8 standard as follows:
    67      *  PrivateKeyInfo ::= SEQUENCE {
     91     *  OneAsymmetricKey ::= SEQUENCE {
    6892     *    version Version,
    6993     *    privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
    7094     *    privateKey PrivateKey,
    71      *    attributes [0] IMPLICIT Attributes OPTIONAL }
     95     *    attributes [0] Attributes OPTIONAL,
     96     *    ...,
     97     *    [[2: publicKey [1] PublicKey OPTIONAL ]],
     98     *    ...
     99     *  }
     100     *
    72101     *  Version ::= INTEGER
    73102     *  PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
    74103     *  PrivateKey ::= OCTET STRING
     104     *  PublicKey ::= OCTET STRING
    75105     *  Attributes ::= SET OF Attribute
    76106     *</pre>
    77107     *
    78108     *<pre>
    79      *  AlgorithmIdentifier ::= SEQUENCE
    80      *  {
    81      *    algorithm           OBJECT IDENTIFIER,
    82      *    parameters          ANY OPTIONAL
     109     *  ... when encoding a OneAsymmetricKey object, the private key is wrapped
     110     *  in a CurvePrivateKey object and wrapped by the OCTET STRING of the
     111     *  'privateKey' field.
     112     *
     113     *  CurvePrivateKey ::= OCTET STRING
     114     *</pre>
     115     *
     116     *<pre>
     117     *  AlgorithmIdentifier  ::=  SEQUENCE  {
     118     *    algorithm   OBJECT IDENTIFIER,
     119     *    parameters  ANY DEFINED BY algorithm OPTIONAL
    83120     *  }
     121     *
     122     *  For all of the OIDs, the parameters MUST be absent.
    84123     *</pre>
    85124     *
    86      *  Ref: https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04
    87      *
    88      *  Note that the private key encoding is not fully specified in the Josefsson draft version 04,
    89      *  and the example could be wrong, as it's lacking Version and AlgorithmIdentifier.
    90      *  This will hopefully be clarified in the next draft.
    91      *  But sun.security.pkcs.PKCS8Key expects them so we must include them for keytool to work.
    92      *
    93      *  This encodes the seed. It will return null if constructed from
    94      *  a spec which was directly constructed from H, in which case seed is null.
    95      *
    96      *  @return 49 bytes for Ed25519, null for other curves
     125     *<pre>
     126     *  id-Ed25519   OBJECT IDENTIFIER ::= { 1 3 101 112 }
     127     *</pre>
     128     *
     129     *  @return 48 bytes for Ed25519, null for other curves
    97130     *  @since implemented in 0.9.25
    98131     */
     132    @Override
    99133    public byte[] getEncoded() {
    100         if (!edDsaSpec.equals(EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512)))
     134        if (!edDsaSpec.equals(EdDSANamedCurveTable.ED_25519_CURVE_SPEC))
    101135            return null;
    102         int totlen = 17 + seed.length;
     136        if (seed == null)
     137            return null;
     138        int totlen = 16 + seed.length;
    103139        byte[] rv = new byte[totlen];
    104140        int idx = 0;
    105141        // sequence
    106142        rv[idx++] = 0x30;
    107         rv[idx++] = (byte) (15 + seed.length);
    108 
     143        rv[idx++] = (byte) (totlen - 2);
    109144        // version
    110         // not in the Josefsson example
    111145        rv[idx++] = 0x02;
    112146        rv[idx++] = 1;
     147        // v1 - no public key included
    113148        rv[idx++] = 0;
    114 
    115149        // Algorithm Identifier
    116150        // sequence
    117         // not in the Josefsson example
    118151        rv[idx++] = 0x30;
    119         rv[idx++] = 8;
    120         // OID 1.3.101.100
     152        rv[idx++] = 5;
     153        // OID
    121154        // https://msdn.microsoft.com/en-us/library/windows/desktop/bb540809%28v=vs.85%29.aspx
    122         // not in the Josefsson example
    123155        rv[idx++] = 0x06;
    124156        rv[idx++] = 3;
    125157        rv[idx++] = (1 * 40) + 3;
    126158        rv[idx++] = 101;
    127         rv[idx++] = 100;
    128         // params
    129         rv[idx++] = 0x0a;
    130         rv[idx++] = 1;
    131         rv[idx++] = 1; // Ed25519
    132         // the key
     159        rv[idx++] = (byte) OID_ED25519;
     160        // params - absent
     161        // PrivateKey
     162        rv[idx++] = 0x04;  // octet string
     163        rv[idx++] = (byte) (2 + seed.length);
     164        // CurvePrivateKey
    133165        rv[idx++] = 0x04;  // octet string
    134166        rv[idx++] = (byte) seed.length;
     167        // the key
    135168        System.arraycopy(seed, 0, rv, idx, seed.length);
    136169        return rv;
     
    138171
    139172    /**
    140      *  This is really dumb for now.
    141      *  See getEncoded().
     173     * Extracts the private key bytes from the provided encoding.
     174     *<p>
     175     * This will decode data conforming to the current spec at
     176     * https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
     177     * or as inferred from the old spec at
     178     * https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04.
     179     *</p><p>
     180     * Contrary to draft-ietf-curdle-pkix-04, it WILL accept a parameter value
     181     * of NULL, as it is required for interoperability with the default Java
     182     * keystore. Other implementations MUST NOT copy this behaviour from here
     183     * unless they also need to read keys from the default Java keystore.
     184     *</p><p>
     185     * This is really dumb for now. It does not use a general-purpose ASN.1 decoder.
     186     * See also getEncoded().
    142187     *
    143188     *  @return 32 bytes for Ed25519, throws for other curves
     
    146191    private static byte[] decode(byte[] d) throws InvalidKeySpecException {
    147192        try {
     193            //
     194            // Setup and OID check
     195            //
     196            int totlen = 48;
     197            int idlen = 5;
     198            int doid = d[OID_BYTE];
     199            if (doid == OID_OLD) {
     200                totlen = 49;
     201                idlen = 8;
     202            } else if (doid == OID_ED25519) {
     203                // Detect parameter value of NULL
     204                if (d[IDLEN_BYTE] == 7) {
     205                    totlen = 50;
     206                    idlen = 7;
     207                }
     208            } else {
     209                throw new InvalidKeySpecException("unsupported key spec");
     210            }
     211
     212            //
     213            // Pre-decoding check
     214            //
     215            if (d.length != totlen) {
     216                throw new InvalidKeySpecException("invalid key spec length");
     217            }
     218
     219            //
     220            // Decoding
     221            //
    148222            int idx = 0;
    149223            if (d[idx++] != 0x30 ||
    150                 d[idx++] != 47 ||
     224                d[idx++] != (totlen - 2) ||
    151225                d[idx++] != 0x02 ||
    152226                d[idx++] != 1 ||
    153227                d[idx++] != 0 ||
    154228                d[idx++] != 0x30 ||
    155                 d[idx++] != 8 ||
     229                d[idx++] != idlen ||
    156230                d[idx++] != 0x06 ||
    157231                d[idx++] != 3 ||
    158232                d[idx++] != (1 * 40) + 3 ||
    159                 d[idx++] != 101 ||
    160                 d[idx++] != 100 ||
    161                 d[idx++] != 0x0a ||
    162                 d[idx++] != 1 ||
    163                 d[idx++] != 1 ||
    164                 d[idx++] != 0x04 ||
     233                d[idx++] != 101) {
     234                throw new InvalidKeySpecException("unsupported key spec");
     235            }
     236            idx++; // OID, checked above
     237            // parameters only with old OID
     238            if (doid == OID_OLD) {
     239                if (d[idx++] != 0x0a ||
     240                    d[idx++] != 1 ||
     241                    d[idx++] != 1) {
     242                    throw new InvalidKeySpecException("unsupported key spec");
     243                }
     244            } else {
     245                // Handle parameter value of NULL
     246                //
     247                // Quote https://tools.ietf.org/html/draft-ietf-curdle-pkix-04 :
     248                //   For all of the OIDs, the parameters MUST be absent.
     249                //   Regardless of the defect in the original 1997 syntax,
     250                //   implementations MUST NOT accept a parameters value of NULL.
     251                //
     252                // But Java's default keystore puts it in (when decoding as
     253                // PKCS8 and then re-encoding to pass on), so we must accept it.
     254                if (idlen == 7) {
     255                    if (d[idx++] != 0x05 ||
     256                        d[idx++] != 0) {
     257                        throw new InvalidKeySpecException("unsupported key spec");
     258                    }
     259                }
     260                // PrivateKey wrapping the CurvePrivateKey
     261                if (d[idx++] != 0x04 ||
     262                    d[idx++] != 34) {
     263                    throw new InvalidKeySpecException("unsupported key spec");
     264                }
     265            }
     266            if (d[idx++] != 0x04 ||
    165267                d[idx++] != 32) {
    166268                throw new InvalidKeySpecException("unsupported key spec");
     
    174276    }
    175277
     278    @Override
    176279    public EdDSAParameterSpec getParams() {
    177280        return edDsaSpec;
  • core/java/src/net/i2p/crypto/eddsa/EdDSAPublicKey.java

    rc65ce1d reff0cac  
    1414 * An EdDSA public key.
    1515 *<p>
    16  * Warning: Public key encoding is is based on the
    17  * current IETF draft, and is subject to change. See getEncoded().
     16 * Warning: Public key encoding is is based on the current curdle WG draft,
     17 * and is subject to change. See getEncoded().
    1818 *</p><p>
    19  * Ref: https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04
     19 * For compatibility with older releases, decoding supports both the old and new
     20 * draft specifications. See decode().
     21 *</p><p>
     22 * Ref: https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
     23 *</p><p>
     24 * Old Ref: https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04
    2025 *</p>
    2126 *
     
    2732    private static final long serialVersionUID = 9837459837498475L;
    2833    private final GroupElement A;
    29     private final GroupElement Aneg;
     34    private GroupElement Aneg;
    3035    private final byte[] Abyte;
    3136    private final EdDSAParameterSpec edDsaSpec;
    3237
     38    // OID 1.3.101.xxx
     39    private static final int OID_OLD = 100;
     40    private static final int OID_ED25519 = 112;
     41    private static final int OID_BYTE = 8;
     42    private static final int IDLEN_BYTE = 3;
     43
    3344    public EdDSAPublicKey(EdDSAPublicKeySpec spec) {
    3445        this.A = spec.getA();
    35         this.Aneg = spec.getNegativeA();
    3646        this.Abyte = this.A.toByteArray();
    3747        this.edDsaSpec = spec.getParams();
     
    4353    public EdDSAPublicKey(X509EncodedKeySpec spec) throws InvalidKeySpecException {
    4454        this(new EdDSAPublicKeySpec(decode(spec.getEncoded()),
    45                                     EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512)));
    46     }
    47 
     55                                    EdDSANamedCurveTable.ED_25519_CURVE_SPEC));
     56    }
     57
     58    @Override
    4859    public String getAlgorithm() {
    49         return "EdDSA";
    50     }
    51 
     60        return KEY_ALGORITHM;
     61    }
     62
     63    @Override
    5264    public String getFormat() {
    5365        return "X.509";
     
    5567
    5668    /**
    57      *  This follows the spec at
    58      *  ref: https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04
    59      *  which matches the docs from
    60      *  java.security.spec.X509EncodedKeySpec
    61      *  quote:
     69     * Returns the public key in its canonical encoding.
     70     *<p>
     71     * This implements the following specs:
     72     *<ul><li>
     73     * General encoding: https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
     74     *</li><li>
     75     * Key encoding: https://tools.ietf.org/html/rfc8032
     76     *</li></ul>
     77     *<p>
     78     * For keys in older formats, decoding and then re-encoding is sufficient to
     79     * migrate them to the canonical encoding.
     80     *</p>
     81     * Relevant spec quotes:
    6282     *<pre>
    63      * The SubjectPublicKeyInfo syntax is defined in the X.509 standard as follows:
    64      *  SubjectPublicKeyInfo ::= SEQUENCE {
    65      *    algorithm AlgorithmIdentifier,
    66      *    subjectPublicKey BIT STRING }
    67      *</pre>
    68      *
    69      *<pre>
    70      *  AlgorithmIdentifier ::= SEQUENCE
    71      *  {
    72      *    algorithm           OBJECT IDENTIFIER,
    73      *    parameters          ANY OPTIONAL
     83     *  In the X.509 certificate, the subjectPublicKeyInfo field has the
     84     *  SubjectPublicKeyInfo type, which has the following ASN.1 syntax:
     85     *
     86     *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
     87     *    algorithm         AlgorithmIdentifier,
     88     *    subjectPublicKey  BIT STRING
    7489     *  }
    7590     *</pre>
    7691     *
    77      *  @return 47 bytes for Ed25519, null for other curves
     92     *<pre>
     93     *  AlgorithmIdentifier  ::=  SEQUENCE  {
     94     *    algorithm   OBJECT IDENTIFIER,
     95     *    parameters  ANY DEFINED BY algorithm OPTIONAL
     96     *  }
     97     *
     98     *  For all of the OIDs, the parameters MUST be absent.
     99     *</pre>
     100     *
     101     *<pre>
     102     *  id-Ed25519   OBJECT IDENTIFIER ::= { 1 3 101 112 }
     103     *</pre>
     104     *
     105     *  @return 44 bytes for Ed25519, null for other curves
    78106     *  @since implemented in 0.9.25
    79107     */
     108    @Override
    80109    public byte[] getEncoded() {
    81         if (!edDsaSpec.equals(EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512)))
     110        if (!edDsaSpec.equals(EdDSANamedCurveTable.ED_25519_CURVE_SPEC))
    82111            return null;
    83         int totlen = 15 + Abyte.length;
     112        int totlen = 12 + Abyte.length;
    84113        byte[] rv = new byte[totlen];
    85114        int idx = 0;
    86115        // sequence
    87116        rv[idx++] = 0x30;
    88         rv[idx++] = (byte) (13 + Abyte.length);
     117        rv[idx++] = (byte) (totlen - 2);
    89118        // Algorithm Identifier
    90119        // sequence
    91120        rv[idx++] = 0x30;
    92         rv[idx++] = 8;
    93         // OID 1.3.101.100
     121        rv[idx++] = 5;
     122        // OID
    94123        // https://msdn.microsoft.com/en-us/library/windows/desktop/bb540809%28v=vs.85%29.aspx
    95124        rv[idx++] = 0x06;
     
    97126        rv[idx++] = (1 * 40) + 3;
    98127        rv[idx++] = 101;
    99         rv[idx++] = 100;
    100         // params
    101         rv[idx++] = 0x0a;
    102         rv[idx++] = 1;
    103         rv[idx++] = 1; // Ed25519
     128        rv[idx++] = (byte) OID_ED25519;
     129        // params - absent
    104130        // the key
    105131        rv[idx++] = 0x03; // bit string
     
    111137
    112138    /**
    113      *  This is really dumb for now.
    114      *  See getEncoded().
     139     * Extracts the public key bytes from the provided encoding.
     140     *<p>
     141     * This will decode data conforming to the current spec at
     142     * https://tools.ietf.org/html/draft-ietf-curdle-pkix-04
     143     * or the old spec at
     144     * https://tools.ietf.org/html/draft-josefsson-pkix-eddsa-04.
     145     *</p><p>
     146     * Contrary to draft-ietf-curdle-pkix-04, it WILL accept a parameter value
     147     * of NULL, as it is required for interoperability with the default Java
     148     * keystore. Other implementations MUST NOT copy this behaviour from here
     149     * unless they also need to read keys from the default Java keystore.
     150     *</p><p>
     151     * This is really dumb for now. It does not use a general-purpose ASN.1 decoder.
     152     * See also getEncoded().
     153     *</p>
    115154     *
    116155     *  @return 32 bytes for Ed25519, throws for other curves
     
    119158    private static byte[] decode(byte[] d) throws InvalidKeySpecException {
    120159        try {
     160            //
     161            // Setup and OID check
     162            //
     163            int totlen = 44;
     164            int idlen = 5;
     165            int doid = d[OID_BYTE];
     166            if (doid == OID_OLD) {
     167                totlen = 47;
     168                idlen = 8;
     169            } else if (doid == OID_ED25519) {
     170                // Detect parameter value of NULL
     171                if (d[IDLEN_BYTE] == 7) {
     172                    totlen = 46;
     173                    idlen = 7;
     174                }
     175            } else {
     176                throw new InvalidKeySpecException("unsupported key spec");
     177            }
     178
     179            //
     180            // Pre-decoding check
     181            //
     182            if (d.length != totlen) {
     183                throw new InvalidKeySpecException("invalid key spec length");
     184            }
     185
     186            //
     187            // Decoding
     188            //
    121189            int idx = 0;
    122190            if (d[idx++] != 0x30 ||
    123                 d[idx++] != 45 ||
     191                d[idx++] != (totlen - 2) ||
    124192                d[idx++] != 0x30 ||
    125                 d[idx++] != 8 ||
     193                d[idx++] != idlen ||
    126194                d[idx++] != 0x06 ||
    127195                d[idx++] != 3 ||
    128196                d[idx++] != (1 * 40) + 3 ||
    129                 d[idx++] != 101 ||
    130                 d[idx++] != 100 ||
    131                 d[idx++] != 0x0a ||
    132                 d[idx++] != 1 ||
    133                 d[idx++] != 1 ||
    134                 d[idx++] != 0x03 ||
     197                d[idx++] != 101) {
     198                throw new InvalidKeySpecException("unsupported key spec");
     199            }
     200            idx++; // OID, checked above
     201            // parameters only with old OID
     202            if (doid == OID_OLD) {
     203                if (d[idx++] != 0x0a ||
     204                    d[idx++] != 1 ||
     205                    d[idx++] != 1) {
     206                    throw new InvalidKeySpecException("unsupported key spec");
     207                }
     208            } else {
     209                // Handle parameter value of NULL
     210                //
     211                // Quote https://tools.ietf.org/html/draft-ietf-curdle-pkix-04 :
     212                //   For all of the OIDs, the parameters MUST be absent.
     213                //   Regardless of the defect in the original 1997 syntax,
     214                //   implementations MUST NOT accept a parameters value of NULL.
     215                //
     216                // But Java's default keystore puts it in (when decoding as
     217                // PKCS8 and then re-encoding to pass on), so we must accept it.
     218                if (idlen == 7) {
     219                    if (d[idx++] != 0x05 ||
     220                        d[idx++] != 0) {
     221                        throw new InvalidKeySpecException("unsupported key spec");
     222                    }
     223                }
     224            }
     225            if (d[idx++] != 0x03 ||
    135226                d[idx++] != 33 ||
    136227                d[idx++] != 0) {
     
    145236    }
    146237
     238    @Override
    147239    public EdDSAParameterSpec getParams() {
    148240        return edDsaSpec;
     
    154246
    155247    public GroupElement getNegativeA() {
    156         return Aneg;
     248        // Only read Aneg once, otherwise read re-ordering might occur between here and return. Requires all GroupElement's fields to be final.
     249        GroupElement ourAneg = Aneg;
     250        if(ourAneg == null) {
     251            ourAneg = A.negate();
     252            Aneg = ourAneg;
     253        }
     254        return ourAneg;
    157255    }
    158256
  • core/java/src/net/i2p/crypto/eddsa/KeyPairGenerator.java

    rc65ce1d reff0cac  
    1818
    1919/**
    20  *  Default strength is 256
     20 *  Default keysize is 256 (Ed25519)
    2121 *
    2222 *  @since 0.9.15
    2323 */
    2424public final class KeyPairGenerator extends KeyPairGeneratorSpi {
    25     private static final int DEFAULT_STRENGTH = 256;
     25    private static final int DEFAULT_KEYSIZE = 256;
    2626    private EdDSAParameterSpec edParams;
    2727    private SecureRandom random;
     
    3333        edParameters = new Hashtable<Integer, AlgorithmParameterSpec>();
    3434
    35         edParameters.put(Integer.valueOf(DEFAULT_STRENGTH), new EdDSAGenParameterSpec(EdDSANamedCurveTable.CURVE_ED25519_SHA512));
     35        edParameters.put(Integer.valueOf(DEFAULT_KEYSIZE), new EdDSAGenParameterSpec(EdDSANamedCurveTable.ED_25519));
    3636    }
    3737
    38     public void initialize(int strength, SecureRandom random) {
    39         AlgorithmParameterSpec edParams = edParameters.get(Integer.valueOf(strength));
     38    public void initialize(int keysize, SecureRandom random) {
     39        AlgorithmParameterSpec edParams = edParameters.get(Integer.valueOf(keysize));
    4040        if (edParams == null)
    4141            throw new InvalidParameterException("unknown key type.");
     
    6262    public KeyPair generateKeyPair() {
    6363        if (!initialized)
    64             initialize(DEFAULT_STRENGTH, RandomSource.getInstance());
     64            initialize(DEFAULT_KEYSIZE, RandomSource.getInstance());
    6565
    6666        byte[] seed = new byte[edParams.getCurve().getField().getb()/8];
  • core/java/src/net/i2p/crypto/eddsa/Utils.java

    rc65ce1d reff0cac  
    22
    33/**
    4  * Basic utilities for eddsa.
     4 * Basic utilities for EdDSA.
    55 * Not for external use, not maintained as a public API.
    66 *
     
    1212    /**
    1313     * Constant-time byte comparison.
     14     * @param b a byte
     15     * @param c a byte
    1416     * @return 1 if b and c are equal, 0 otherwise.
    1517     */
     
    2527    /**
    2628     * Constant-time byte[] comparison.
     29     * @param b a byte[]
     30     * @param c a byte[]
    2731     * @return 1 if b and c are equal, 0 otherwise.
    2832     */
  • core/java/src/net/i2p/crypto/eddsa/math/Curve.java

    rc65ce1d reff0cac  
    2020    private final GroupElement zeroP2;
    2121    private final GroupElement zeroP3;
     22    private final GroupElement zeroP3PrecomputedDouble;
    2223    private final GroupElement zeroPrecomp;
    2324
     
    3132        FieldElement one = f.ONE;
    3233        zeroP2 = GroupElement.p2(this, zero, one, one);
    33         zeroP3 = GroupElement.p3(this, zero, one, one, zero);
     34        zeroP3 = GroupElement.p3(this, zero, one, one, zero, false);
     35        zeroP3PrecomputedDouble = GroupElement.p3(this, zero, one, one, zero, true);
    3436        zeroPrecomp = GroupElement.precomp(this, one, one, zero);
    3537    }
     
    5759        case P3:
    5860            return zeroP3;
     61        case P3PrecomputedDouble:
     62            return zeroP3PrecomputedDouble;
    5963        case PRECOMP:
    6064            return zeroPrecomp;
     
    6569
    6670    public GroupElement createPoint(byte[] P, boolean precompute) {
    67         GroupElement ge = new GroupElement(this, P);
    68         if (precompute)
    69             ge.precompute(true);
     71        GroupElement ge = new GroupElement(this, P, precompute);
    7072        return ge;
    7173    }
  • core/java/src/net/i2p/crypto/eddsa/math/FieldElement.java

    rc65ce1d reff0cac  
    6464    public abstract FieldElement pow22523();
    6565
     66    /**
     67     * @since 0.9.36
     68     */
     69    public abstract FieldElement cmov(FieldElement val, final int b);
     70
    6671    // Note: concrete subclasses must implement hashCode() and equals()
    6772}
  • core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java

    rc65ce1d reff0cac  
    4141        /** Extended (P^3): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT */
    4242        P3,
     43        /**
     44         * Can only be requested.  Results in P3 representation but also populates dblPrecmp.
     45         * @since 0.9.36
     46         */
     47        P3PrecomputedDouble,
    4348        /** Completed (P x P): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T */
    4449        P1P1,
     
    8287            final FieldElement Z,
    8388            final FieldElement T) {
    84         return new GroupElement(curve, Representation.P3, X, Y, Z, T);
     89        return p3(curve, X, Y, Z, T, false);
     90    }
     91
     92    /**
     93     * Creates a new group element in P3 representation, potentially with pre-computation.
     94     *
     95     * @param curve The curve.
     96     * @param X The X coordinate.
     97     * @param Y The Y coordinate.
     98     * @param Z The Z coordinate.
     99     * @param T The T coordinate.
     100     * @param precomputeDoubleOnly If true, populate dblPrecmp, else set to null.
     101     * @return The group element in P3 representation.
     102     * @since 0.9.36
     103     */
     104    public static GroupElement p3(
     105            final Curve curve,
     106            final FieldElement X,
     107            final FieldElement Y,
     108            final FieldElement Z,
     109            final FieldElement T,
     110            final boolean precomputeDoubleOnly) {
     111        return new GroupElement(curve, Representation.P3, X, Y, Z, T, precomputeDoubleOnly);
    85112    }
    86113
     
    176203     * Variable is package private only so that tests run.
    177204     */
    178     GroupElement[][] precmp;
     205    final GroupElement[][] precmp;
    179206
    180207    /**
     
    184211     * Variable is package private only so that tests run.
    185212     */
    186     GroupElement[] dblPrecmp;
    187 
    188     /**
    189      * Creates a group element for a curve.
     213    final GroupElement[] dblPrecmp;
     214
     215    /**
     216     * Creates a group element for a curve, without any pre-computation.
    190217     *
    191218     * @param curve The curve.
     
    203230            final FieldElement Z,
    204231            final FieldElement T) {
     232        this(curve, repr, X, Y, Z, T, false);
     233    }
     234
     235    /**
     236     * Creates a group element for a curve, with optional pre-computation.
     237     *
     238     * @param curve The curve.
     239     * @param repr The representation used to represent the group element.
     240     * @param X The X coordinate.
     241     * @param Y The Y coordinate.
     242     * @param Z The Z coordinate.
     243     * @param T The T coordinate.
     244     * @param precomputeDouble If true, populate dblPrecmp, else set to null.
     245     * @since 0.9.36
     246     */
     247    public GroupElement(
     248            final Curve curve,
     249            final Representation repr,
     250            final FieldElement X,
     251            final FieldElement Y,
     252            final FieldElement Z,
     253            final FieldElement T,
     254            final boolean precomputeDouble) {
    205255        this.curve = curve;
    206256        this.repr = repr;
     
    209259        this.Z = Z;
    210260        this.T = T;
     261        this.precmp = null;
     262        this.dblPrecmp = precomputeDouble ? precomputeDouble() : null;
    211263    }
    212264
     
    216268     * A point (x,y) is encoded by storing y in bit 0 to bit 254 and the sign of x in bit 255.
    217269     * x is recovered in the following way:
    218      * <p><ul>
     270     * </p><ul>
    219271     * <li>x = sign(x) * sqrt((y^2 - 1) / (d * y^2 + 1)) = sign(x) * sqrt(u / v) with u = y^2 - 1 and v = d * y^2 + 1.
     272     * <li>Setting  = (u * v^3) * (u * v^7)^((q - 5) / 8) one has ^2 = +-(u / v).
     273     * <li>If v *  = -u multiply  with i=sqrt(-1).
     274     * <li>Set x := .
     275     * <li>If sign(x) != bit 255 of s then negate x.
     276     * </ul>
     277     *
     278     * @param curve The curve.
     279     * @param s The encoded point.
     280     */
     281    public GroupElement(final Curve curve, final byte[] s) {
     282        this(curve, s, false);
     283    }
     284
     285    /**
     286     * Creates a group element for a curve from a given encoded point.  With optional pre-computation.
     287     * <p>
     288     * A point (x,y) is encoded by storing y in bit 0 to bit 254 and the sign of x in bit 255.
     289     * x is recovered in the following way:
     290     * </p><ul>
     291     * <li>x = sign(x) * \sqrt{(y^2 - 1) / (d * y^2 + 1)} = sign(x) * \sqrt{u / v} with u = y^2 - 1 and v = d * y^2 + 1.
    220292     * <li>Setting β = (u * v^3) * (u * v^7)^((q - 5) / 8) one has β^2 = +-(u / v).
    221293     * <li>If v * β = -u multiply β with i=sqrt(-1).
     
    226298     * @param curve The curve.
    227299     * @param s The encoded point.
    228      */
    229     public GroupElement(final Curve curve, final byte[] s) {
     300     * @param precomputeSingleAndDouble If true, populate both precmp and dblPrecmp, else set both to null.
     301     * @since 0.9.36
     302     */
     303    public GroupElement(final Curve curve, final byte[] s, boolean precomputeSingleAndDouble) {
    230304        FieldElement x, y, yy, u, v, v3, vxx, check;
    231305        y = curve.getField().fromByteArray(s);
     
    242316
    243317        // x = (v3^2)vu, aka x = uv^7
    244         x = v3.square().multiply(v).multiply(u);   
     318        x = v3.square().multiply(v).multiply(u);
    245319
    246320        //  x = (uv^7)^((q-5)/8)
     
    270344        this.Z = curve.getField().ONE;
    271345        this.T = this.X.multiply(this.Y);
     346        if (precomputeSingleAndDouble) {
     347            precmp = precomputeSingle();
     348            dblPrecmp = precomputeDouble();
     349        } else {
     350            precmp = null;
     351            dblPrecmp = null;
     352        }
    272353    }
    273354
     
    369450
    370451    /**
     452     * Converts the group element to the P3 representation, with dblPrecmp populated.
     453     *
     454     * @return The group element in the P3 representation.
     455     * @since 0.9.36
     456     */
     457    public GroupElement toP3PrecomputeDouble() {
     458        return toRep(Representation.P3PrecomputedDouble);
     459    }
     460
     461    /**
    371462     * Converts the group element to the CACHED representation.
    372463     *
     
    383474     * <p>
    384475     * Supported conversions:
    385      * <p><ul>
     476     * </p><ul>
    386477     * <li>P3 -> P2
    387478     * <li>P3 -> CACHED (1 multiply, 1 add, 1 subtract)
     
    417508                        return p2(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T));
    418509                    case P3:
    419                         return p3(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T), this.X.multiply(this.Y));
     510                        return p3(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T), this.X.multiply(this.Y), false);
     511                    case P3PrecomputedDouble:
     512                        return p3(this.curve, this.X.multiply(this.T), Y.multiply(this.Z), this.Z.multiply(this.T), this.X.multiply(this.Y), true);
    420513                    case P1P1:
    421514                        return p1p1(this.curve, this.X, this.Y, this.Z, this.T);
     
    443536
    444537    /**
    445      * Precomputes several tables.
    446      * <p>
    447      * The precomputed tables are used for {@link #scalarMultiply(byte[])}
    448      * and {@link #doubleScalarMultiplyVariableTime(GroupElement, byte[], byte[])}.
    449      *
    450      * @param precomputeSingle should the matrix for scalarMultiply() be precomputed?
    451      */
    452     public synchronized void precompute(final boolean precomputeSingle) {
    453         GroupElement Bi;
    454 
    455         if (precomputeSingle && this.precmp == null) {
    456             // Precomputation for single scalar multiplication.
    457             this.precmp = new GroupElement[32][8];
    458             // TODO-CR BR: check that this == base point when the method is called.
    459             Bi = this;
    460             for (int i = 0; i < 32; i++) {
    461                 GroupElement Bij = Bi;
    462                 for (int j = 0; j < 8; j++) {
    463                     final FieldElement recip = Bij.Z.invert();
    464                     final FieldElement x = Bij.X.multiply(recip);
    465                     final FieldElement y = Bij.Y.multiply(recip);
    466                     this.precmp[i][j] = precomp(this.curve, y.add(x), y.subtract(x), x.multiply(y).multiply(this.curve.get2D()));
    467                     Bij = Bij.add(Bi.toCached()).toP3();
    468                 }
    469                 // Only every second summand is precomputed (16^2 = 256)
    470                 for (int k = 0; k < 8; k++) {
    471                     Bi = Bi.add(Bi.toCached()).toP3();
    472                 }
     538     * Precomputes table for {@link #scalarMultiply(byte[])}.
     539     * @since 0.9.36 split out from precompute()
     540     */
     541    private GroupElement[][] precomputeSingle() {
     542        // Precomputation for single scalar multiplication.
     543        GroupElement[][] precmp = new GroupElement[32][8];
     544        // TODO-CR BR: check that this == base point when the method is called.
     545        GroupElement Bi = this;
     546        for (int i = 0; i < 32; i++) {
     547            GroupElement Bij = Bi;
     548            for (int j = 0; j < 8; j++) {
     549                final FieldElement recip = Bij.Z.invert();
     550                final FieldElement x = Bij.X.multiply(recip);
     551                final FieldElement y = Bij.Y.multiply(recip);
     552                precmp[i][j] = precomp(this.curve, y.add(x), y.subtract(x), x.multiply(y).multiply(this.curve.get2D()));
     553                Bij = Bij.add(Bi.toCached()).toP3();
    473554            }
    474         }
    475 
     555            // Only every second summand is precomputed (16^2 = 256)
     556            for (int k = 0; k < 8; k++) {
     557                Bi = Bi.add(Bi.toCached()).toP3();
     558            }
     559        }
     560        return precmp;
     561    }
     562
     563    /**
     564     * Precomputes table for {@link #doubleScalarMultiplyVariableTime(GroupElement, byte[], byte[])}.
     565     * @since 0.9.36 split out from precompute()
     566     */
     567    private GroupElement[] precomputeDouble() {
    476568        // Precomputation for double scalar multiplication.
    477569        // P,3P,5P,7P,9P,11P,13P,15P
    478         if (this.dblPrecmp != null)
    479             return;
    480         this.dblPrecmp = new GroupElement[8];
    481         Bi = this;
     570        GroupElement[] dblPrecmp = new GroupElement[8];
     571        GroupElement Bi = this;
    482572        for (int i = 0; i < 8; i++) {
    483573            final FieldElement recip = Bi.Z.invert();
    484574            final FieldElement x = Bi.X.multiply(recip);
    485575            final FieldElement y = Bi.Y.multiply(recip);
    486             this.dblPrecmp[i] = precomp(this.curve, y.add(x), y.subtract(x), x.multiply(y).multiply(this.curve.get2D()));
     576            dblPrecmp[i] = precomp(this.curve, y.add(x), y.subtract(x), x.multiply(y).multiply(this.curve.get2D()));
    487577            // Bi = edwards(B,edwards(B,Bi))
    488578            Bi = this.add(this.add(Bi.toCached()).toP3().toCached()).toP3();
    489579        }
     580        return dblPrecmp;
    490581    }
    491582
     
    497588     * <p>
    498589     * r = ((X' : Z'), (Y' : T')) where
    499      * <p><ul>
     590     * </p><ul>
    500591     * <li>X' = (X + Y)^2 - (Y^2 + X^2)
    501592     * <li>Y' = Y^2 + X^2
     
    506597     * <p>
    507598     * r = (X'' : Y'' : Z'') where
    508      * <p><ul>
     599     * </p><ul>
    509600     * <li>X'' = X' * Z' = ((X + Y)^2 - Y^2 - X^2) * (2 * Z^2 - (y^2 - X^2))
    510601     * <li>Y'' = Y' * T' = (Y^2 + X^2) * (2 * Z^2 - (y^2 - X^2))
     
    549640     * <p>
    550641     * r = ((X' : Z'), (Y' : T')) where
    551      * <p><ul>
     642     * </p><ul>
    552643     * <li>X' = (Y1 + X1) * q.X - (Y1 - X1) * q.Y = ((Y1 + X1) * (Y2 + X2) - (Y1 - X1) * (Y2 - X2)) * 1/Z2
    553644     * <li>Y' = (Y1 + X1) * q.X + (Y1 - X1) * q.Y = ((Y1 + X1) * (Y2 + X2) + (Y1 - X1) * (Y2 - X2)) * 1/Z2
     
    556647     * </ul><p>
    557648     * Setting A = (Y1 - X1) * (Y2 - X2), B = (Y1 + X1) * (Y2 + X2), C = 2 * d * T1 * T2, D = 2 * Z1 * Z2 we get
    558      * <p><ul>
     649     * </p><ul>
    559650     * <li>X' = (B - A) * 1/Z2
    560651     * <li>Y' = (B + A) * 1/Z2
     
    565656     * <p>
    566657     * r = (X'' : Y'' : Z'' : T'') where
    567      * <p><ul>
     658     * </p><ul>
    568659     * <li>X'' = X' * Z' = (B - A) * (D + C) * 1/Z2^2
    569660     * <li>Y'' = Y' * T' = (B + A) * (D - C) * 1/Z2^2
     
    635726     * <p>
    636727     * r in P x P representation:
    637      * <p><ul>
     728     * </p><ul>
    638729     * <li>X' = (Y1 + X1) * (Y2 + X2) - (Y1 - X1) * (Y2 - X2)
    639730     * <li>Y' = (Y1 + X1) * (Y2 + X2) + (Y1 - X1) * (Y2 - X2)
     
    642733     * </ul><p>
    643734     * Setting A = (Y1 - X1) * (Y2 - X2), B = (Y1 + X1) * (Y2 + X2), C = 2 * d * T1 * T2, D = 2 * Z1 * Z2 we get
    644      * <p><ul>
     735     * </p><ul>
    645736     * <li>X' = (B - A)
    646737     * <li>Y' = (B + A)
     
    709800        if (this.repr != Representation.P3)
    710801            throw new UnsupportedOperationException();
    711         return this.curve.getZero(Representation.P3).sub(toCached()).toP3();
     802        return this.curve.getZero(Representation.P3).sub(toCached()).toP3PrecomputeDouble();
    712803    }
    713804
     
    805896     * @param u The group element to return if b == 1.
    806897     * @param b in {0, 1}
    807      * @return u if b == 1; this if b == 0; null otherwise.
     898     * @return u if b == 1; this if b == 0; Results undefined if b is not in {0, 1}.
    808899     */
    809900    GroupElement cmov(final GroupElement u, final int b) {
    810         GroupElement ret = null;
    811         for (int i = 0; i < b; i++) {
    812             // Only for b == 1
    813             ret = u;
    814         }
    815         for (int i = 0; i < 1-b; i++) {
    816             // Only for b == 0
    817             ret = this;
    818         }
    819         return ret;
     901        return precomp(curve, X.cmov(u.X, b), Y.cmov(u.Y, b), Z.cmov(u.Z, b));
    820902    }
    821903
     
    874956
    875957        GroupElement h = this.curve.getZero(Representation.P3);
    876         synchronized(this) {
    877             // TODO: Get opinion from a crypto professional.
    878             // This should in practice never be necessary, the only point that
    879             // this should get called on is EdDSA's B.
    880             //precompute();
    881             for (i = 1; i < 64; i += 2) {
    882                 t = select(i/2, e[i]);
    883                 h = h.madd(t).toP3();
    884             }
    885 
    886             h = h.dbl().toP2().dbl().toP2().dbl().toP2().dbl().toP3();
    887 
    888             for (i = 0; i < 64; i += 2) {
    889                 t = select(i/2, e[i]);
    890                 h = h.madd(t).toP3();
    891             }
     958        for (i = 1; i < 64; i += 2) {
     959            t = select(i/2, e[i]);
     960            h = h.madd(t).toP3();
     961        }
     962
     963        h = h.dbl().toP2().dbl().toP2().dbl().toP2().dbl().toP3();
     964
     965        for (i = 0; i < 64; i += 2) {
     966            t = select(i/2, e[i]);
     967            h = h.madd(t).toP3();
    892968        }
    893969
     
    9661042        }
    9671043
    968         synchronized(this) {
    969             // TODO-CR BR strange comment below.
    970             // TODO: Get opinion from a crypto professional.
    971             // This should in practice never be necessary, the only point that
    972             // this should get called on is EdDSA's B.
    973             //precompute();
    974             for (; i >= 0; --i) {
    975                 GroupElement t = r.dbl();
     1044        for (; i >= 0; --i) {
     1045            GroupElement t = r.dbl();
    9761046
    9771047                if (aslide[i] > 0) {
     
    9871057                }
    9881058
    989                 r = t.toP2();
    990             }
     1059            r = t.toP2();
    9911060        }
    9921061
  • core/java/src/net/i2p/crypto/eddsa/math/bigint/BigIntegerFieldElement.java

    rc65ce1d reff0cac  
    9494    }
    9595
     96    /**
     97     * @since 0.9.36
     98     */
     99    @Override
     100    public FieldElement cmov(FieldElement val, int b) {
     101        // Not constant-time, but it doesn't really matter because none of the underlying BigInteger operations
     102        // are either, so there's not much point in trying hard here ...
     103        return b == 0 ? this : val;
     104    }
     105
    96106    @Override
    97107    public int hashCode() {
  • core/java/src/net/i2p/crypto/eddsa/math/ed25519/Ed25519FieldElement.java

    rc65ce1d reff0cac  
    5252     * <p>
    5353     * Preconditions:
    54      * <p><ul>
     54     * </p><ul>
    5555     * <li>|f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
    5656     * <li>|g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
    5757     * </ul><p>
    5858     * Postconditions:
    59      * <p><ul>
     59     * </p><ul>
    6060     * <li>|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
    6161     * </ul>
     
    8181     * <p>
    8282     * Preconditions:
    83      * <p><ul>
     83     * </p><ul>
    8484     * <li>|f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
    8585     * <li>|g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
    8686     * </ul><p>
    8787     * Postconditions:
    88      * <p><ul>
     88     * </p><ul>
    8989     * <li>|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
    9090     * </ul>
     
    108108     * <p>
    109109     * Preconditions:
    110      * <p><ul>
     110     * </p><ul>
    111111     * <li>|f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
    112112     * </ul><p>
    113113     * Postconditions:
    114      * <p><ul>
     114     * </p><ul>
    115115     * <li>|h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
    116116     * </ul>
     
    132132     * <p>
    133133     * Preconditions:
    134      * <p><ul>
     134     * </p><ul>
    135135     * <li>|f| bounded by
    136136     * 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
     
    139139     * </ul><p>
    140140     * Postconditions:
    141      * <p><ul>
     141     * </p><ul>
    142142     * <li>|h| bounded by
    143143     * 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
     
    383383     * <p>
    384384     * Preconditions:
    385      * <p><ul>
     385     * </p><ul>
    386386     * <li>|f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
    387387     * </ul><p>
    388388     * Postconditions:
    389      * <p><ul>
     389     * </p><ul>
    390390     * <li>|h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
    391391     * </ul><p>
     
    539539     * <p>
    540540     * Preconditions:
    541      * <p><ul>
     541     * </p><ul>
    542542     * <li>|f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
    543543     * </ul><p>
    544544     * Postconditions:
    545      * <p><ul>
     545     * </p><ul>
    546546     * <li>|h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
    547547     * </ul><p>
     
    935935    }
    936936
     937    /**
     938     * Constant-time conditional move. Well, actually it is a conditional copy.
     939     * Logic is inspired by the SUPERCOP implementation at:
     940     *   https://github.com/floodyberry/supercop/blob/master/crypto_sign/ed25519/ref10/fe_cmov.c
     941     *
     942     * @param val the other field element.
     943     * @param b must be 0 or 1, otherwise results are undefined.
     944     * @return a copy of this if b == 0, or a copy of val if b == 1.
     945     * @since 0.9.36
     946     */
     947    @Override
     948    public FieldElement cmov(FieldElement val, int b) {
     949        Ed25519FieldElement that = (Ed25519FieldElement) val;
     950        b = -b;
     951        int[] result = new int[10];
     952        for (int i = 0; i < 10; i++) {
     953            result[i] = this.t[i];
     954            int x = this.t[i] ^ that.t[i];
     955            x &= b;
     956            result[i] ^= x;
     957        }
     958        return new Ed25519FieldElement(this.f, result);
     959    }
     960
    937961    @Override
    938962    public int hashCode() {
  • core/java/src/net/i2p/crypto/eddsa/spec/EdDSANamedCurveTable.java

    rc65ce1d reff0cac  
    11package net.i2p.crypto.eddsa.spec;
    22
    3 import java.util.Hashtable;
     3import java.util.HashMap;
     4import java.util.Locale;
    45
    56import net.i2p.crypto.eddsa.Utils;
     
    1718 */
    1819public class EdDSANamedCurveTable {
     20    /** RFC 8032 */
     21    public static final String ED_25519 = "Ed25519";
     22    /** old name */
    1923    public static final String CURVE_ED25519_SHA512 = "ed25519-sha-512";
    2024
     
    2832            ed25519field.fromByteArray(Utils.hexToBytes("b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b"))); // I
    2933
    30     private static final EdDSANamedCurveSpec ed25519sha512 = new EdDSANamedCurveSpec(
    31             CURVE_ED25519_SHA512,
     34    public static final EdDSANamedCurveSpec ED_25519_CURVE_SPEC = new EdDSANamedCurveSpec(
     35            ED_25519,
    3236            ed25519curve,
    3337            "SHA-512", // H
     
    3741                    true)); // Precompute tables for B
    3842
    39     private static final Hashtable<String, EdDSANamedCurveSpec> curves = new Hashtable<String, EdDSANamedCurveSpec>();
     43    private static volatile HashMap<String, EdDSANamedCurveSpec> curves = new HashMap<String, EdDSANamedCurveSpec>();
    4044
    41     public static void defineCurve(String name, EdDSANamedCurveSpec curve) {
    42         curves.put(name, curve);
     45    private static synchronized void putCurve(String name, EdDSANamedCurveSpec curve) {
     46        HashMap<String, EdDSANamedCurveSpec> newCurves = new HashMap<String, EdDSANamedCurveSpec>(curves);
     47        newCurves.put(name, curve);
     48        curves = newCurves;
     49    }
     50
     51    public static void defineCurve(EdDSANamedCurveSpec curve) {
     52        putCurve(curve.getName().toLowerCase(Locale.ENGLISH), curve);
     53    }
     54
     55    static void defineCurveAlias(String name, String alias) {
     56        EdDSANamedCurveSpec curve = curves.get(name.toLowerCase(Locale.ENGLISH));
     57        if (curve == null) {
     58            throw new IllegalStateException();
     59        }
     60        putCurve(alias.toLowerCase(Locale.ENGLISH), curve);
    4361    }
    4462
    4563    static {
    46         defineCurve(CURVE_ED25519_SHA512, ed25519sha512);
     64        // RFC 8032
     65        defineCurve(ED_25519_CURVE_SPEC);
     66        // old name
     67        defineCurveAlias(ED_25519, CURVE_ED25519_SHA512);
    4768    }
    4869
    4970    public static EdDSANamedCurveSpec getByName(String name) {
    50         return curves.get(name);
     71        return curves.get(name.toLowerCase(Locale.ENGLISH));
    5172    }
    5273}
  • core/java/src/net/i2p/crypto/eddsa/spec/EdDSAParameterSpec.java

    rc65ce1d reff0cac  
    2626
    2727    /**
     28     *  @param curve the curve
     29     *  @param hashAlgo the JCA string for the hash algorithm
     30     *  @param sc the parameter L represented as ScalarOps
     31     *  @param B the parameter B
    2832     *  @throws IllegalArgumentException if hash algorithm is unsupported or length is wrong
    2933     */
  • core/java/src/net/i2p/crypto/eddsa/spec/EdDSAPrivateKeySpec.java

    rc65ce1d reff0cac  
    2222
    2323    /**
     24     *  @param seed the private key
     25     *  @param spec the parameter specification for this key
    2426     *  @throws IllegalArgumentException if seed length is wrong or hash algorithm is unsupported
    2527     */
     
    5961     *  getSeed() will return null if this constructor is used.
    6062     *
     63     *  @param spec the parameter specification for this key
    6164     *  @param h the private key
    6265     *  @throws IllegalArgumentException if hash length is wrong
  • core/java/src/net/i2p/crypto/eddsa/spec/EdDSAPublicKeySpec.java

    rc65ce1d reff0cac  
    1313public class EdDSAPublicKeySpec implements KeySpec {
    1414    private final GroupElement A;
    15     private final GroupElement Aneg;
     15    private GroupElement Aneg;
    1616    private final EdDSAParameterSpec spec;
    1717
    1818    /**
     19     *  @param pk the public key
     20     *  @param spec the parameter specification for this key
    1921     *  @throws IllegalArgumentException if key length is wrong
    2022     */
     
    2426
    2527        this.A = new GroupElement(spec.getCurve(), pk);
    26         // Precompute -A for use in verification.
    27         this.Aneg = A.negate();
    28         Aneg.precompute(false);
    2928        this.spec = spec;
    3029    }
     
    3231    public EdDSAPublicKeySpec(GroupElement A, EdDSAParameterSpec spec) {
    3332        this.A = A;
    34         this.Aneg = A.negate();
    35         Aneg.precompute(false);
    3633        this.spec = spec;
    3734    }
     
    4239
    4340    public GroupElement getNegativeA() {
    44         return Aneg;
     41        // Only read Aneg once, otherwise read re-ordering might occur between here and return. Requires all GroupElement's fields to be final.
     42        GroupElement ourAneg = Aneg;
     43        if(ourAneg == null) {
     44            ourAneg = A.negate();
     45            Aneg = ourAneg;
     46        }
     47        return ourAneg;
    4548    }
    4649
  • core/java/src/net/i2p/crypto/eddsa/spec/package.html

    rc65ce1d reff0cac  
    11<html><body>
    22<p>
    3    Specifications for curves and keys, and a table for named curves,
    4    initially containing only the 25519 curve "ed25519-sha-512".
     3   Specifications for curves and keys, and a table for named curves.
     4   Contains the following curves:
    55</p>
     6<ul>
     7   <li>"Ed25519"</li>
     8</ul>
    69</body></html>
  • core/java/test/junit/net/i2p/crypto/eddsa/math/GroupElementTest.java

    rc65ce1d reff0cac  
    761761        GroupElement B = ed25519.getB();
    762762        GroupElement geZero = curve.getZero(GroupElement.Representation.P3);
    763         geZero.precompute(false);
     763        //geZero.precompute(false);
    764764
    765765        // 0 * GE(0) + 0 * GE(0) = GE(0)
     
    803803            final GroupElement basePoint = ed25519.getB();
    804804            final GroupElement g = MathUtils.getRandomGroupElement();
    805             g.precompute(false);
     805            //g.precompute(false);
    806806            final FieldElement f1 = MathUtils.getRandomFieldElement();
    807807            final FieldElement f2 = MathUtils.getRandomFieldElement();
Note: See TracChangeset for help on using the changeset viewer.