Changeset 5842e25


Ignore:
Timestamp:
Dec 24, 2013 4:41:05 PM (8 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
e8e2396
Parents:
bf485d8
Message:

Initial support for key certificates and arbitrary types and lengths
of signing keys and signatures in RouterIdentities? and Destinations.
Untested, not even for regressions, except with command line
using PrivateKeyFile?.
Based on preliminary spec at http://zzz.i2p/topics/1442?page=1#p7524
Not done:

  • Transport handshake signing
  • Configuration of default type
  • Specification of type in options to I2PSocketManagerFactory
  • Specification of type in i2ptunnel
  • Fix up caching of SigningPublicKey? and P256 key cert
  • Any non-default crypto type in the key cert
  • Documentation
Files:
1 added
20 edited

Legend:

Unmodified
Added
Removed
  • apps/streaming/java/src/net/i2p/client/streaming/Packet.java

    rbf485d8 r5842e25  
    66
    77import net.i2p.I2PAppContext;
     8import net.i2p.crypto.SigType;
    89import net.i2p.data.Base64;
    910import net.i2p.data.ByteArray;
     
    437438        if (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED))
    438439            optionSize += 2;
    439         if (isFlagSet(FLAG_SIGNATURE_INCLUDED))
    440             optionSize += Signature.SIGNATURE_BYTES;
     440        if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
     441            optionSize += _optionSignature.length();
     442        }
    441443       
    442444        DataHelper.toLong(buffer, cur, 2, optionSize);
     
    456458        if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
    457459            if (includeSig)
    458                 System.arraycopy(_optionSignature.getData(), 0, buffer, cur, Signature.SIGNATURE_BYTES);
     460                System.arraycopy(_optionSignature.getData(), 0, buffer, cur, _optionSignature.length());
    459461            else // we're signing (or validating)
    460                 Arrays.fill(buffer, cur, cur+Signature.SIGNATURE_BYTES, (byte)0x0);
    461             cur += Signature.SIGNATURE_BYTES;
     462                Arrays.fill(buffer, cur, cur + _optionSignature.length(), (byte)0x0);
     463            cur += _optionSignature.length();
    462464        }
    463465       
     
    512514            size += 2;
    513515        if (isFlagSet(FLAG_SIGNATURE_INCLUDED))
    514             size += Signature.SIGNATURE_BYTES;
     516            size += _optionSignature.length();
    515517       
    516518        size += 2; // option size
     
    607609        }
    608610        if (isFlagSet(FLAG_SIGNATURE_INCLUDED)) {
    609             Signature optionSignature = new Signature();
    610             byte buf[] = new byte[Signature.SIGNATURE_BYTES];
    611             System.arraycopy(buffer, cur, buf, 0, Signature.SIGNATURE_BYTES);
     611            Signature optionSignature;
     612            Destination from = getOptionalFrom();
     613            if (from != null) {
     614                optionSignature = new Signature(from.getSigningPublicKey().getType());
     615            } else {
     616                // super cheat for now, look for correct type,
     617                // assume no more options. If we add to the options
     618                // we will have to ask the manager.
     619                int siglen = payloadBegin - cur;
     620                SigType type = null;
     621                for (SigType t : SigType.values()) {
     622                    if (t.getSigLen() == siglen) {
     623                        type = t;
     624                        break;
     625                    }
     626                }
     627                if (type == null) {
     628                    if (siglen < Signature.SIGNATURE_BYTES)
     629                        throw new IllegalArgumentException("unknown sig type len=" + siglen);
     630                    // Hope it's the default type with some unknown options following;
     631                    // if not the sig will fail later
     632                    type = SigType.DSA_SHA1;
     633                    siglen = Signature.SIGNATURE_BYTES;
     634                }
     635                optionSignature = new Signature(type);
     636            }
     637            byte buf[] = new byte[optionSignature.length()];
     638            System.arraycopy(buffer, cur, buf, 0, buf.length);
    612639            optionSignature.setData(buf);
    613640            setOptionalSignature(optionSignature);
    614             cur += Signature.SIGNATURE_BYTES;
     641            cur += buf.length;
    615642        }
    616643    }
     
    668695        int size = writePacket(buffer, offset, false);
    669696        _optionSignature = ctx.dsa().sign(buffer, offset, size, key);
    670         if (false) {
    671             Log l = ctx.logManager().getLog(Packet.class);
    672             l.error("Signing: " + toString());
    673             l.error(Base64.encode(buffer, 0, size));
    674             l.error("Signature: " + Base64.encode(_optionSignature.getData()));
    675         }
     697        //if (false) {
     698        //    Log l = ctx.logManager().getLog(Packet.class);
     699        //    l.error("Signing: " + toString());
     700        //    l.error(Base64.encode(buffer, 0, size));
     701        //    l.error("Signature: " + Base64.encode(_optionSignature.getData()));
     702        //}
    676703        // jump into the signed data and inject the signature where we
    677704        // previously placed a bunch of zeroes
     
    688715                              + (isFlagSet(FLAG_FROM_INCLUDED) ? _optionFrom.size() : 0)
    689716                              + (isFlagSet(FLAG_MAX_PACKET_SIZE_INCLUDED) ? 2 : 0);
    690         System.arraycopy(_optionSignature.getData(), 0, buffer, signatureOffset, Signature.SIGNATURE_BYTES);
     717        System.arraycopy(_optionSignature.getData(), 0, buffer, signatureOffset, _optionSignature.length());
    691718        return size;
    692719    }
  • core/java/src/net/i2p/client/I2PClient.java

    rbf485d8 r5842e25  
    1616
    1717import net.i2p.I2PException;
     18import net.i2p.crypto.SigType;
    1819import net.i2p.data.Certificate;
    1920import net.i2p.data.Destination;
     
    8485    public Destination createDestination(OutputStream destKeyStream) throws I2PException, IOException;
    8586
     87    /**
     88     * Create a destination with the given signature type.
     89     * It will have a null certificate for DSA 1024/160 and KeyCertificate otherwise.
     90     * This is not bound to the I2PClient, you must supply the data back again
     91     * in createSession().
     92     *
     93     * @param destKeyStream location to write out the destination, PrivateKey, and SigningPrivateKey,
     94     *                      format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
     95     * @since 0.9.11
     96     */
     97    public Destination createDestination(OutputStream destKeyStream, SigType type) throws I2PException, IOException;
     98
    8699    /** Create a new destination with the given certificate and store it, along with the private
    87100     * encryption and signing keys at the specified location
  • core/java/src/net/i2p/client/I2PClientImpl.java

    rbf485d8 r5842e25  
    1313import java.io.InputStream;
    1414import java.io.OutputStream;
     15import java.security.GeneralSecurityException;
    1516import java.util.Properties;
    1617
     
    1819import net.i2p.I2PException;
    1920import net.i2p.crypto.KeyGenerator;
     21import net.i2p.crypto.SigType;
    2022import net.i2p.data.Certificate;
    2123import net.i2p.data.Destination;
     24import net.i2p.data.KeyCertificate;
    2225import net.i2p.data.PrivateKey;
    2326import net.i2p.data.PublicKey;
    2427import net.i2p.data.SigningPrivateKey;
    2528import net.i2p.data.SigningPublicKey;
     29import net.i2p.data.SimpleDataStructure;
     30import net.i2p.util.RandomSource;
    2631
    2732/**
     
    3540
    3641    /**
    37      * Create the destination with a null payload.
     42     * Create a destination with a DSA 1024/160 signature type and a null certificate.
    3843     * This is not bound to the I2PClient, you must supply the data back again
    3944     * in createSession().
     
    4348     */
    4449    public Destination createDestination(OutputStream destKeyStream) throws I2PException, IOException {
    45         Certificate cert = new Certificate();
    46         cert.setCertificateType(Certificate.CERTIFICATE_TYPE_NULL);
    47         cert.setPayload(null);
     50        return createDestination(destKeyStream, SigType.DSA_SHA1);
     51    }
     52
     53    /**
     54     * Create a destination with the given signature type.
     55     * It will have a null certificate for DSA 1024/160 and KeyCertificate otherwise.
     56     * This is not bound to the I2PClient, you must supply the data back again
     57     * in createSession().
     58     *
     59     * @param destKeyStream location to write out the destination, PrivateKey, and SigningPrivateKey,
     60     *                      format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
     61     * @since 0.9.11
     62     */
     63    public Destination createDestination(OutputStream destKeyStream, SigType type) throws I2PException, IOException {
     64        Certificate cert;
     65        if (type == SigType.DSA_SHA1) {
     66            cert = Certificate.NULL_CERT;
     67        } else {
     68            cert = new KeyCertificate(type);
     69        }
    4870        return createDestination(destKeyStream, cert);
    4971    }
     
    5375     * the PrivateKey and SigningPrivateKey to the destKeyStream
    5476     *
     77     * If cert is a KeyCertificate, the signing keypair will be of the specified type.
     78     * The KeyCertificate data must be .............................
     79     * The padding if any will be randomized. The extra key data if any will be set in the
     80     * key cert.
     81     *
    5582     * @param destKeyStream location to write out the destination, PrivateKey, and SigningPrivateKey,
    5683     *                      format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
     
    5885    public Destination createDestination(OutputStream destKeyStream, Certificate cert) throws I2PException, IOException {
    5986        Destination d = new Destination();
    60         d.setCertificate(cert);
    6187        Object keypair[] = KeyGenerator.getInstance().generatePKIKeypair();
    6288        PublicKey publicKey = (PublicKey) keypair[0];
    6389        PrivateKey privateKey = (PrivateKey) keypair[1];
    64         Object signingKeys[] = KeyGenerator.getInstance().generateSigningKeypair();
     90        SimpleDataStructure signingKeys[];
     91        if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
     92            KeyCertificate kcert = cert.toKeyCertificate();
     93            SigType type = kcert.getSigType();
     94            try {
     95                signingKeys = KeyGenerator.getInstance().generateSigningKeys(type);
     96            } catch (GeneralSecurityException gse) {
     97                throw new I2PException("keygen fail", gse);
     98            }
     99        } else {
     100            signingKeys = KeyGenerator.getInstance().generateSigningKeys();
     101        }
    65102        SigningPublicKey signingPubKey = (SigningPublicKey) signingKeys[0];
    66103        SigningPrivateKey signingPrivKey = (SigningPrivateKey) signingKeys[1];
    67104        d.setPublicKey(publicKey);
    68105        d.setSigningPublicKey(signingPubKey);
     106        if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
     107            // fix up key certificate or padding
     108            KeyCertificate kcert = cert.toKeyCertificate();
     109            SigType type = kcert.getSigType();
     110            int len = type.getPubkeyLen();
     111            if (len < 128) {
     112                byte[] pad = new byte[128 - len];
     113                RandomSource.getInstance().nextBytes(pad);
     114                d.setPadding(pad);
     115            } else if (len > 128) {
     116                System.arraycopy(signingPubKey.getData(), 128, kcert.getPayload(), KeyCertificate.HEADER_LENGTH, len - 128);
     117            }
     118        }
     119        d.setCertificate(cert);
    69120
    70121        d.writeBytes(destKeyStream);
  • core/java/src/net/i2p/client/I2PSessionImpl.java

    rbf485d8 r5842e25  
    6363    private final PrivateKey _privateKey;
    6464    /** private key for signing */
    65     private final SigningPrivateKey _signingPrivateKey;
     65    private   /* final */  SigningPrivateKey _signingPrivateKey;
    6666    /** configuration options */
    6767    private final Properties _options;
     
    374374        _myDestination.readBytes(destKeyStream);
    375375        _privateKey.readBytes(destKeyStream);
     376        _signingPrivateKey = new SigningPrivateKey(_myDestination.getSigningPublicKey().getType());
    376377        _signingPrivateKey.readBytes(destKeyStream);
    377378    }
  • core/java/src/net/i2p/client/I2PSimpleClient.java

    rbf485d8 r5842e25  
    1313import net.i2p.I2PAppContext;
    1414import net.i2p.I2PException;
     15import net.i2p.crypto.SigType;
    1516import net.i2p.data.Certificate;
    1617import net.i2p.data.Destination;
     
    2122 */
    2223public class I2PSimpleClient implements I2PClient {
    23     /** @deprecated Don't do this */
     24
     25    /**
     26     *  @deprecated Don't do this
     27     *  @throws UnsupportedOperationException always
     28     */
    2429    public Destination createDestination(OutputStream destKeyStream) throws I2PException, IOException {
    25         return null;
     30        throw new UnsupportedOperationException();
    2631    }
    2732
    28     /** @deprecated or this */
     33    /**
     34     *  @deprecated Don't do this
     35     *  @throws UnsupportedOperationException always
     36     *  @since 0.9.11
     37     */
     38    public Destination createDestination(OutputStream destKeyStream, SigType type) throws I2PException, IOException {
     39        throw new UnsupportedOperationException();
     40    }
     41
     42    /**
     43     *  @deprecated Don't do this
     44     *  @throws UnsupportedOperationException always
     45     */
    2946    public Destination createDestination(OutputStream destKeyStream, Certificate cert) throws I2PException, IOException {
    30         return null;
     47        throw new UnsupportedOperationException();
    3148    }
    3249
     
    3855        return createSession(I2PAppContext.getGlobalContext(), options);
    3956    }
     57
    4058    /**
    4159     * Create a new session (though do not connect it yet)
  • core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java

    rbf485d8 r5842e25  
    1515import net.i2p.I2PAppContext;
    1616import net.i2p.crypto.KeyGenerator;
     17import net.i2p.crypto.SigType;
    1718import net.i2p.data.DataFormatException;
    1819import net.i2p.data.DataHelper;
     
    106107        try {
    107108            leaseSet.sign(session.getPrivateKey());
     109            // Workaround for unparsable serialized signing private key for revocation
     110            // Send him a dummy DSA_SHA1 private key since it's unused anyway
     111            // See CreateLeaseSetMessage.doReadMessage()
     112            SigningPrivateKey spk = li.getSigningPrivateKey();
     113            if (!_context.isRouterContext() && spk.getType() != SigType.DSA_SHA1) {
     114                byte[] dummy = new byte[SigningPrivateKey.KEYSIZE_BYTES];
     115                _context.random().nextBytes(dummy);
     116                spk = new SigningPrivateKey(dummy);
     117            }
    108118            session.getProducer().createLeaseSet(session, leaseSet, li.getSigningPrivateKey(), li.getPrivateKey());
    109119            session.setLeaseSet(leaseSet);
  • core/java/src/net/i2p/client/datagram/I2PDatagramDissector.java

    rbf485d8 r5842e25  
    1515import net.i2p.crypto.DSAEngine;
    1616import net.i2p.crypto.SHA256Generator;
     17import net.i2p.crypto.SigType;
    1718import net.i2p.data.DataFormatException;
    1819import net.i2p.data.Destination;
     
    6869            // read destination
    6970            rxDest = Destination.create(dgStream);
    70             rxSign = new Signature();
     71            SigType type = rxDest.getSigningPublicKey().getType();
     72            if (type != null)
     73                throw new DataFormatException("unsupported sig type");
     74            rxSign = new Signature(type);
    7175            // read signature
    7276            rxSign.readBytes(dgStream);
  • core/java/src/net/i2p/crypto/SU3File.java

    rbf485d8 r5842e25  
    524524     *  @since 0.9.9
    525525     */
    526     private static SigType parseSigType(String stype) {
    527         try {
    528             return SigType.valueOf(stype.toUpperCase(Locale.US));
    529         } catch (IllegalArgumentException iae) {
    530             try {
    531                 int code = Integer.parseInt(stype);
    532                 return SigType.getByCode(code);
    533             } catch (NumberFormatException nfe) {
    534                 return null;
    535              }
    536         }
    537     }
    538     /**
    539      *  @param stype number or name
    540      *  @return null if not found
    541      *  @since 0.9.9
    542      */
    543526    private static ContentType parseContentType(String ctype) {
    544527        try {
     
    628611    private static final boolean signCLI(String stype, String ctype, String inputFile, String signedFile,
    629612                                         String privateKeyFile, String version, String signerName, String keypw) {
    630         SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : parseSigType(stype);
     613        SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : SigType.parseSigType(stype);
    631614        if (type == null) {
    632615            System.out.println("Signature type " + stype + " is not supported");
     
    720703     */
    721704    private static final boolean genKeysCLI(String stype, String publicKeyFile, String privateKeyFile, String alias) {
    722         SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : parseSigType(stype);
     705        SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : SigType.parseSigType(stype);
    723706        if (type == null) {
    724707            System.out.println("Signature type " + stype + " is not supported");
  • core/java/src/net/i2p/crypto/SigType.java

    rbf485d8 r5842e25  
    66import java.security.spec.InvalidParameterSpecException;
    77import java.util.HashMap;
     8import java.util.Locale;
    89import java.util.Map;
    910
     
    171172        return BY_CODE.get(Integer.valueOf(code));
    172173    }
     174
     175    /**
     176     *  Convenience for user apps
     177     *
     178     *  @param stype number or name
     179     *  @return null if not found
     180     *  @since 0.9.9 moved from SU3File in 0.9.11
     181     */
     182    public static SigType parseSigType(String stype) {
     183        try {
     184            return valueOf(stype.toUpperCase(Locale.US));
     185        } catch (IllegalArgumentException iae) {
     186            try {
     187                int code = Integer.parseInt(stype);
     188                return getByCode(code);
     189            } catch (NumberFormatException nfe) {
     190                return null;
     191             }
     192        }
     193    }
    173194}
  • core/java/src/net/i2p/data/Certificate.java

    rbf485d8 r5842e25  
    4343    /** Contains multiple certs */
    4444    public final static int CERTIFICATE_TYPE_MULTIPLE = 4;
     45    /** @since 0.9.11 */
     46    public final static int CERTIFICATE_TYPE_KEY = 5;
    4547
    4648    /**
     
    5961        byte[] payload = new byte[length];
    6062        System.arraycopy(data, off + 3, payload, 0, length);
     63        if (type == CERTIFICATE_TYPE_KEY) {
     64            try {
     65                return new KeyCertificate(payload);
     66            } catch (DataFormatException dfe) {
     67                throw new IllegalArgumentException(dfe);
     68            }
     69        }
    6170        return new Certificate(type, payload);
    6271    }
     
    7887        if (read != length)
    7988            throw new DataFormatException("Not enough bytes for the payload (read: " + read + " length: " + length + ')');
     89        if (type == CERTIFICATE_TYPE_KEY)
     90            return new KeyCertificate(payload);
    8091        return new Certificate(type, payload);
    8192    }
     
    8495    }
    8596
     97    /**
     98     *  @throws IllegalArgumentException if type < 0
     99     */
    86100    public Certificate(int type, byte[] payload) {
     101        if (type < 0)
     102            throw new IllegalArgumentException();
    87103        _type = type;
    88104        _payload = payload;
     
    94110    }
    95111
     112    /**
     113     *  @throws IllegalArgumentException if type < 0
     114     *  @throws IllegalStateException if already set
     115     */
    96116    public void setCertificateType(int type) {
     117        if (type < 0)
     118            throw new IllegalArgumentException();
     119        if (_type != 0 && _type != type)
     120            throw new IllegalStateException("already set");
    97121        _type = type;
    98122    }
     
    102126    }
    103127
     128    /**
     129     *  @throws IllegalStateException if already set
     130     */
    104131    public void setPayload(byte[] payload) {
     132        if (_payload != null)
     133            throw new IllegalStateException("already set");
    105134        _payload = payload;
    106135    }
    107136   
     137    /**
     138     *  @throws IllegalStateException if already set
     139     */
    108140    public void readBytes(InputStream in) throws DataFormatException, IOException {
     141        if (_type != 0 || _payload != null)
     142            throw new IllegalStateException("already set");
    109143        _type = (int) DataHelper.readLong(in, 1);
    110144        int length = (int) DataHelper.readLong(in, 2);
     
    150184    }
    151185   
     186    /**
     187     *  @throws IllegalStateException if already set
     188     */
    152189    public int readBytes(byte source[], int offset) throws DataFormatException {
     190        if (_type != 0 || _payload != null)
     191            throw new IllegalStateException("already set");
    153192        if (source == null) throw new DataFormatException("Cert is null");
    154193        if (source.length < offset + 3)
     
    176215    }
    177216   
     217    /**
     218     *  Up-convert this to a KeyCertificate
     219     *
     220     *  @throws DataFormatException if cert type != CERTIFICATE_TYPE_KEY
     221     *  @since 0.9.11
     222     */
     223    public KeyCertificate toKeyCertificate() throws DataFormatException {
     224        if (_type != CERTIFICATE_TYPE_KEY)
     225            throw new DataFormatException("type");
     226        return new KeyCertificate(this);
     227    }
     228
    178229    @Override
    179230    public boolean equals(Object object) {
     
    195246        if (getCertificateType() == CERTIFICATE_TYPE_NULL)
    196247            buf.append("Null certificate");
     248        else if (getCertificateType() == CERTIFICATE_TYPE_KEY)
     249            buf.append("Key certificate");
    197250        else if (getCertificateType() == CERTIFICATE_TYPE_HASHCASH)
    198251            buf.append("Hashcash certificate");
  • core/java/src/net/i2p/data/Destination.java

    rbf485d8 r5842e25  
    101101        System.arraycopy(_publicKey.getData(), 0, target, cur, PublicKey.KEYSIZE_BYTES);
    102102        cur += PublicKey.KEYSIZE_BYTES;
    103         System.arraycopy(_signingKey.getData(), 0, target, cur, SigningPublicKey.KEYSIZE_BYTES);
    104         cur += SigningPublicKey.KEYSIZE_BYTES;
     103        if (_padding != null) {
     104            System.arraycopy(_padding, 0, target, cur, _padding.length);
     105            cur += _padding.length;
     106        }
     107        System.arraycopy(_signingKey.getData(), 0, target, cur, _signingKey.length());
     108        cur += _signingKey.length();
    105109        cur += _certificate.writeBytes(target, cur);
    106110        return cur - offset;
     
    108112   
    109113    /**
    110      * @deprecated was used only by Packet.java in streaming, now unused
     114     * deprecated was used only by Packet.java in streaming, now unused
    111115     *
    112116     * @throws IllegalStateException if data already set
    113117     */
     118/****
    114119    public int readBytes(byte source[], int offset) throws DataFormatException {
    115120        if (source == null) throw new DataFormatException("Null source");
     
    131136        return cur - offset;
    132137    }
     138****/
    133139
    134140    public int size() {
    135         return PublicKey.KEYSIZE_BYTES + SigningPublicKey.KEYSIZE_BYTES + _certificate.size();
     141        return PublicKey.KEYSIZE_BYTES + _signingKey.length() + _certificate.size();
    136142    }
    137143
  • core/java/src/net/i2p/data/KeysAndCert.java

    rbf485d8 r5842e25  
    3636    protected Certificate _certificate;
    3737    protected Hash __calculatedHash;
     38    protected byte[] _padding;
    3839
    3940    public Certificate getCertificate() {
     
    8081   
    8182    /**
     83     * @throws IllegalStateException if was already set
     84     * @since 0.9.11
     85     */
     86    public void setPadding(byte[] padding) {
     87        if (_padding != null)
     88            throw new IllegalStateException();
     89        _padding = padding;
     90        __calculatedHash = null;
     91    }
     92   
     93    /**
    8294     * @throws IllegalStateException if data already set
    8395     */
     
    8698            throw new IllegalStateException();
    8799        _publicKey = PublicKey.create(in);
    88         _signingKey = SigningPublicKey.create(in);
    89         _certificate = Certificate.create(in);
     100        SigningPublicKey spk = SigningPublicKey.create(in);
     101        Certificate  cert = Certificate.create(in);
     102        if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
     103            // convert SPK to new SPK and padding
     104            KeyCertificate kcert = cert.toKeyCertificate();
     105            _signingKey = spk.toTypedKey(kcert);
     106            _padding = spk.getPadding(kcert);
     107            _certificate = kcert;
     108        } else {
     109            _signingKey = spk;
     110            _certificate = cert;
     111        }
    90112        __calculatedHash = null;
    91113    }
     
    95117            throw new DataFormatException("Not enough data to format the router identity");
    96118        _publicKey.writeBytes(out);
    97         _signingKey.writeBytes(out);
     119        if (_padding != null)
     120            out.write(_padding);
     121        _signingKey.writeTruncatedBytes(out);
    98122        _certificate.writeBytes(out);
    99123    }
     
    107131               DataHelper.eq(_signingKey, ident._signingKey)
    108132               && DataHelper.eq(_publicKey, ident._publicKey)
     133               && DataHelper.eq(_padding, ident._padding)
    109134               && DataHelper.eq(_certificate, ident._certificate);
    110135    }
     
    126151        buf.append("\n\tPublicKey: ").append(_publicKey);
    127152        buf.append("\n\tSigningPublicKey: ").append(_signingKey);
     153        if (_padding != null)
     154            buf.append("\n\tPadding: ").append(_padding.length).append(" bytes");
    128155        buf.append(']');
    129156        return buf.toString();
  • core/java/src/net/i2p/data/LeaseSet.java

    rbf485d8 r5842e25  
    276276        if ((_destination == null) || (_encryptionKey == null) || (_signingKey == null))
    277277            return null;
    278         int len = PublicKey.KEYSIZE_BYTES  // dest
    279                 + SigningPublicKey.KEYSIZE_BYTES // dest
    280                 + 3 // cert minimum, could be more, only used to size the BAOS
     278        int len = _destination.size()
    281279                + PublicKey.KEYSIZE_BYTES // encryptionKey
    282                 + SigningPublicKey.KEYSIZE_BYTES // signingKey
     280                + _signingKey.length() // signingKey
    283281                + 1
    284282                + _leases.size() * 44; // leases
     
    311309        _destination = Destination.create(in);
    312310        _encryptionKey = PublicKey.create(in);
    313         _signingKey = SigningPublicKey.create(in);
     311        // revocation signing key must be same type as the destination signing key
     312        _signingKey = new SigningPublicKey(_destination.getSigningPublicKey().getType());
     313        _signingKey.readBytes(in);
    314314        int numLeases = (int) DataHelper.readLong(in, 1);
    315315        if (numLeases > MAX_LEASES)
     
    321321            addLease(lease);
    322322        }
    323         _signature = new Signature();
     323        // signature must be same type as the destination signing key
     324        _signature = new Signature(_destination.getSigningPublicKey().getType());
    324325        _signature.readBytes(in);
    325326    }
     
    346347     */
    347348    public int size() {
    348         return PublicKey.KEYSIZE_BYTES //destination.pubKey
    349              + SigningPublicKey.KEYSIZE_BYTES // destination.signPubKey
    350              + _destination.getCertificate().size() // destination.certificate, usually 3
     349        return _destination.size()
    351350             + PublicKey.KEYSIZE_BYTES // encryptionKey
    352              + SigningPublicKey.KEYSIZE_BYTES // signingKey
     351             + _signingKey.length() // signingKey
    353352             + 1 // number of leases
    354353             + _leases.size() * (Hash.HASH_LENGTH + 4 + 8);
  • core/java/src/net/i2p/data/PrivateKeyFile.java

    rbf485d8 r5842e25  
    77import java.io.FileOutputStream;
    88import java.io.IOException;
     9import java.security.GeneralSecurityException;
     10import java.util.Locale;
    911import java.util.Map;
    1012import java.util.Properties;
     
    1820import net.i2p.client.I2PSessionException;
    1921import net.i2p.crypto.DSAEngine;
     22import net.i2p.crypto.KeyGenerator;
     23import net.i2p.crypto.SigType;
     24import net.i2p.util.RandomSource;
    2025
    2126/**
     
    5156     */
    5257    public static void main(String args[]) {
    53         if (args.length == 0) {
     58        if (args.length == 0 ||
     59            (args[0].startsWith("-") && args.length == 1) ||
     60            (args[0].equals("-t") && args.length != 3)) {
    5461            System.err.println("Usage: PrivateKeyFile filename (generates if nonexistent, then prints)");
    5562            System.err.println("       PrivateKeyFile -h filename (generates if nonexistent, adds hashcash cert)");
     
    5966            System.err.println("       PrivateKeyFile -u filename (changes to unknown cert)");
    6067            System.err.println("       PrivateKeyFile -x filename (changes to hidden cert)");
     68            System.err.println("       PrivateKeyFile -t sigtype filename (changes to KeyCertificate of the given sig type");
    6169            return;
    6270        }
     
    6573        int filearg = 0;
    6674        if (args.length > 1) {
    67             if (args.length >= 2 && args[0].equals("-h"))
     75            if (args.length >= 2 && (args[0].equals("-h") || args[0].equals("-t")))
    6876                filearg = args.length - 1;
    6977            else
     
    102110                pkf.setSignedCert(pkf2);
    103111                System.out.println("New destination with signed cert is:");
     112            } else if (args.length == 3 && args[0].equals("-t")) {
     113                // KeyCert
     114                SigType type = SigType.parseSigType(args[1]);
     115                if (type == null)
     116                    throw new IllegalArgumentException("Signature type " + args[1] + " is not supported");
     117                pkf.setKeyCert(type);
     118                System.out.println("New destination with key cert is:");
    104119            }
    105120            System.out.println(pkf);
    106121            pkf.write();
    107             verifySignature(d);
     122            verifySignature(pkf.getDestination());
    108123        } catch (Exception e) {
    109124            e.printStackTrace();
     
    205220        newdest.setPublicKey(dest.getPublicKey());
    206221        newdest.setSigningPublicKey(dest.getSigningPublicKey());
     222        newdest.setCertificate(c);
     223        dest = newdest;
     224        return c;
     225    }
     226   
     227    /**
     228     * Change cert type - caller must also call write().
     229     * Side effect - creates new Destination object.
     230     * @since 0.9.11
     231     */
     232    public Certificate setKeyCert(SigType type) {
     233        if (type == SigType.DSA_SHA1)
     234            return setCertType(Certificate.CERTIFICATE_TYPE_NULL);
     235        if (dest == null)
     236            throw new IllegalArgumentException("Dest is null");
     237        KeyCertificate c = new KeyCertificate(type);
     238        SimpleDataStructure signingKeys[];
     239        try {
     240            signingKeys = KeyGenerator.getInstance().generateSigningKeys(type);
     241        } catch (GeneralSecurityException gse) {
     242            throw new RuntimeException("keygen fail", gse);
     243        }
     244        SigningPublicKey signingPubKey = (SigningPublicKey) signingKeys[0];
     245        signingPrivKey = (SigningPrivateKey) signingKeys[1];
     246        // dests now immutable, must create new
     247        Destination newdest = new Destination();
     248        newdest.setPublicKey(dest.getPublicKey());
     249        newdest.setSigningPublicKey(signingPubKey);
     250        // fix up key certificate or padding
     251        int len = type.getPubkeyLen();
     252        if (len < 128) {
     253            byte[] pad = new byte[128 - len];
     254            RandomSource.getInstance().nextBytes(pad);
     255            newdest.setPadding(pad);
     256        } else if (len > 128) {
     257            System.arraycopy(signingPubKey.getData(), 128, c.getPayload(), KeyCertificate.HEADER_LENGTH, len - 128);
     258        }
    207259        newdest.setCertificate(c);
    208260        dest = newdest;
     
    445497    private static final int HASH_EFFORT = VerifiedDestination.MIN_HASHCASH_EFFORT;
    446498   
    447    
    448    
    449499    private final File file;
    450500    private final I2PClient client;
  • core/java/src/net/i2p/data/RouterInfo.java

    rbf485d8 r5842e25  
    555555        }
    556556        DataHelper.readProperties(din, _options);
    557         _signature = new Signature();
     557        _signature = new Signature(_identity.getSigningPublicKey().getType());
    558558        _signature.readBytes(in);
    559559
  • core/java/src/net/i2p/data/Signature.java

    rbf485d8 r5842e25  
    1414/**
    1515 * Defines the signature as defined by the I2P data structure spec.
    16  * A signature is a 40-byte array verifying the authenticity of some data
     16 * By default, a signature is a 40-byte array verifying the authenticity of some data
    1717 * using the DSA-SHA1 algorithm.
    1818 *
    1919 * The signature is the 20-byte R followed by the 20-byte S,
    2020 * both are unsigned integers.
     21 *
     22 * As of release 0.9.8, signatures of arbitrary length and type are supported.
     23 * See SigType.
    2124 *
    2225 * @author jrandom
     
    4043
    4144    /**
     45     *  Unknown type not allowed as we won't know the length to read in the data.
     46     *
     47     *  @param type non-null
    4248     *  @since 0.9.8
    4349     */
    4450    public Signature(SigType type) {
    4551        super();
     52        if (type == null)
     53            throw new IllegalArgumentException("unknown type");
    4654        _type = type;
    4755    }
     
    5260
    5361    /**
     62     *  Should we allow an unknown type here?
     63     *
     64     *  @param type non-null
    5465     *  @since 0.9.8
    5566     */
    5667    public Signature(SigType type, byte data[]) {
    5768        super();
     69        if (type == null)
     70            throw new IllegalArgumentException("unknown type");
    5871        _type = type;
    5972        setData(data);
     
    6578
    6679    /**
     80     *  @return non-null
    6781     *  @since 0.9.8
    6882     */
  • core/java/src/net/i2p/data/SigningPrivateKey.java

    rbf485d8 r5842e25  
    1515/**
    1616 * Defines the SigningPrivateKey as defined by the I2P data structure spec.
    17  * A signing private key is 20 byte Integer. The private key represents only the
     17 * A signing private key is by default a 20 byte Integer. The private key represents only the
    1818 * exponent, not the primes, which are constant and defined in the crypto spec.
    1919 * This key varies from the PrivateKey in its usage (signing, not decrypting)
     20 *
     21 * As of release 0.9.8, keys of arbitrary length and type are supported.
     22 * See SigType.
    2023 *
    2124 * @author jrandom
  • core/java/src/net/i2p/data/SigningPublicKey.java

    rbf485d8 r5842e25  
    1212import java.io.InputStream;
    1313import java.io.IOException;
     14import java.io.OutputStream;
    1415
    1516import net.i2p.crypto.SigType;
     
    1718/**
    1819 * Defines the SigningPublicKey as defined by the I2P data structure spec.
    19  * A signing public key is 128 byte Integer. The public key represents only the
     20 * A signing public key is by default 128 byte Integer. The public key represents only the
    2021 * exponent, not the primes, which are constant and defined in the crypto spec.
    2122 * This key varies from the PrivateKey in its usage (verifying signatures, not encrypting)
     23 *
     24 * As of release 0.9.8, keys of arbitrary length and type are supported.
     25 * See SigType.
    2226 *
    2327 * @author jrandom
     
    5660
    5761    /**
     62     *  @param type if null, type is unknown
    5863     *  @since 0.9.8
    5964     */
     
    6873
    6974    /**
     75     *  @param type if null, type is unknown
    7076     *  @since 0.9.8
    7177     */
     
    7379        super();
    7480        _type = type;
    75         setData(data);
     81        if (type != null || data == null)
     82            setData(data);
     83        else
     84            _data = data;  // bypass length check
    7685    }
    7786
     
    8594    }
    8695
     96    /**
     97     *  @return if type unknown, the length of the data, or 128 if no data
     98     */
    8799    public int length() {
    88         return _type.getPubkeyLen();
     100        if (_type != null)
     101            return _type.getPubkeyLen();
     102        if (_data != null)
     103            return _data.length;
     104        return KEYSIZE_BYTES;
    89105    }
    90106
    91107    /**
     108     *  @return null if unknown
    92109     *  @since 0.9.8
    93110     */
    94111    public SigType getType() {
    95112        return _type;
     113    }
     114
     115    /**
     116     *  Up-convert this from an untyped (type 0) SPK to a typed SPK based on the Key Cert given
     117     *
     118     *  @throws IllegalArgumentException if this is already typed to a different type
     119     *  @since 0.9.11
     120     */
     121    public SigningPublicKey toTypedKey(KeyCertificate kcert) {
     122        if (_data == null)
     123            throw new IllegalStateException();
     124        SigType newType = kcert.getSigType();
     125        if (_type == newType)
     126            return this;
     127        if (_type != SigType.DSA_SHA1)
     128            throw new IllegalArgumentException("Cannot convert " + _type + " to " + newType);
     129        int newLen = newType.getPubkeyLen();
     130        if (newLen == SigType.DSA_SHA1.getPubkeyLen())
     131            return new SigningPublicKey(newType, _data);
     132        byte[] newData = new byte[newLen];
     133        if (newLen < SigType.DSA_SHA1.getPubkeyLen()) {
     134            // right-justified
     135            System.arraycopy(_data, _data.length - newLen, newData, 0, newLen);
     136        } else {
     137            // full 128 bytes + fragment in kcert
     138            System.arraycopy(_data, 0, newData, 0, _data.length);
     139            System.arraycopy(kcert.getPayload(), KeyCertificate.HEADER_LENGTH, newData, _data.length, newLen - _data.length);
     140        }
     141        return new SigningPublicKey(newType, newData);
     142    }
     143
     144    /**
     145     *  Get the portion of this (type 0) SPK that is really padding based on the Key Cert type given,
     146     *  if any
     147     *
     148     *  @return leading padding length > 0 or null
     149     *  @throws IllegalArgumentException if this is already typed to a different type
     150     *  @since 0.9.11
     151     */
     152    public byte[] getPadding(KeyCertificate kcert) {
     153        if (_data == null)
     154            throw new IllegalStateException();
     155        SigType newType = kcert.getSigType();
     156        if (_type == newType)
     157            return null;
     158        if (_type != SigType.DSA_SHA1)
     159            throw new IllegalStateException("Cannot convert " + _type + " to " + newType);
     160        int newLen = newType.getPubkeyLen();
     161        if (newLen >= SigType.DSA_SHA1.getPubkeyLen())
     162            return null;
     163        int padLen = SigType.DSA_SHA1.getPubkeyLen() - newLen;
     164        byte[] pad = new byte[padLen];
     165        System.arraycopy(_data, 0, pad, 0, padLen);
     166        return pad;
     167    }
     168   
     169    /**
     170     *  Write the data up to a max of 128 bytes.
     171     *  If longer, the rest will be written in the KeyCertificate.
     172     *  @since 0.9.11
     173     */
     174    public void writeTruncatedBytes(OutputStream out) throws DataFormatException, IOException {
     175        if (_type.getPubkeyLen() <= KEYSIZE_BYTES)
     176            out.write(_data);
     177        else
     178            out.write(_data, 0, KEYSIZE_BYTES);
    96179    }
    97180
  • core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java

    rbf485d8 r5842e25  
    7272            _sessionId = new SessionId();
    7373            _sessionId.readBytes(in);
     74            // Revocation is unimplemented.
     75            // As the SPK comes before the LeaseSet, we don't know the key type.
     76            // We could have some sort of callback or state setting so we get the
     77            // expected type from the session. But for now, we just assume it's 20 bytes.
     78            // Clients outside router context should throw in a dummy 20 bytes.
    7479            _signingPrivateKey = new SigningPrivateKey();
    7580            _signingPrivateKey.readBytes(in);
     
    8893            throw new I2CPMessageException("Unable to write out the message as there is not enough data");
    8994        int size = 4 // sessionId
    90                  + SigningPrivateKey.KEYSIZE_BYTES
     95                 + _signingPrivateKey.length()
    9196                 + PrivateKey.KEYSIZE_BYTES
    9297                 + _leaseSet.size();
  • core/java/src/net/i2p/data/i2cp/SessionConfig.java

    rbf485d8 r5842e25  
    190190        _options = DataHelper.readProperties(rawConfig);
    191191        _creationDate = DataHelper.readDate(rawConfig);
    192         _signature = new Signature();
     192        _signature = new Signature(_destination.getSigningPublicKey().getType());
    193193        _signature.readBytes(rawConfig);
    194194    }
Note: See TracChangeset for help on using the changeset viewer.