propagate from branch 'i2p.i2p.zzz.ecdsa' (head e83bcdc842f5995d310a4295147f9326a993e010)

to branch 'i2p.i2p' (head 4983f716f8740bc7ddfae5561a562a0d42a815ae)
This commit is contained in:
zzz
2014-02-17 13:29:41 +00:00
34 changed files with 996 additions and 144 deletions

View File

@ -15,6 +15,7 @@ import java.io.OutputStream;
import java.util.Properties;
import net.i2p.I2PException;
import net.i2p.crypto.SigType;
import net.i2p.data.Certificate;
import net.i2p.data.Destination;
@ -40,6 +41,11 @@ public interface I2PClient {
/** @since 0.8.1 */
public final static String PROP_RELIABILITY_NONE = "none";
/** @since 0.9.12 */
public static final String PROP_SIGTYPE = "i2cp.destination.sigType";
/** @since 0.9.12 */
public static final SigType DEFAULT_SIGTYPE = SigType.DSA_SHA1;
/**
* For router->client payloads.
*
@ -83,6 +89,18 @@ public interface I2PClient {
*/
public Destination createDestination(OutputStream destKeyStream) throws I2PException, IOException;
/**
* Create a destination with the given signature type.
* It will have a null certificate for DSA 1024/160 and KeyCertificate otherwise.
* This is not bound to the I2PClient, you must supply the data back again
* in createSession().
*
* @param destKeyStream location to write out the destination, PrivateKey, and SigningPrivateKey,
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
* @since 0.9.12
*/
public Destination createDestination(OutputStream destKeyStream, SigType type) throws I2PException, IOException;
/** Create a new destination with the given certificate and store it, along with the private
* encryption and signing keys at the specified location
*

View File

@ -12,17 +12,22 @@ package net.i2p.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.crypto.KeyGenerator;
import net.i2p.crypto.SigType;
import net.i2p.data.Certificate;
import net.i2p.data.Destination;
import net.i2p.data.KeyCertificate;
import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey;
import net.i2p.data.SimpleDataStructure;
import net.i2p.util.RandomSource;
/**
* Base client implementation.
@ -34,7 +39,7 @@ import net.i2p.data.SigningPublicKey;
class I2PClientImpl implements I2PClient {
/**
* Create the destination with a null payload.
* Create a destination with a DSA 1024/160 signature type and a null certificate.
* This is not bound to the I2PClient, you must supply the data back again
* in createSession().
*
@ -42,9 +47,26 @@ class I2PClientImpl implements I2PClient {
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
*/
public Destination createDestination(OutputStream destKeyStream) throws I2PException, IOException {
Certificate cert = new Certificate();
cert.setCertificateType(Certificate.CERTIFICATE_TYPE_NULL);
cert.setPayload(null);
return createDestination(destKeyStream, DEFAULT_SIGTYPE);
}
/**
* Create a destination with the given signature type.
* It will have a null certificate for DSA 1024/160 and KeyCertificate otherwise.
* This is not bound to the I2PClient, you must supply the data back again
* in createSession().
*
* @param destKeyStream location to write out the destination, PrivateKey, and SigningPrivateKey,
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
* @since 0.9.12
*/
public Destination createDestination(OutputStream destKeyStream, SigType type) throws I2PException, IOException {
Certificate cert;
if (type == SigType.DSA_SHA1) {
cert = Certificate.NULL_CERT;
} else {
cert = new KeyCertificate(type);
}
return createDestination(destKeyStream, cert);
}
@ -52,20 +74,49 @@ class I2PClientImpl implements I2PClient {
* Create the destination with the given payload and write it out along with
* the PrivateKey and SigningPrivateKey to the destKeyStream
*
* If cert is a KeyCertificate, the signing keypair will be of the specified type.
* The KeyCertificate data must be .............................
* The padding if any will be randomized. The extra key data if any will be set in the
* key cert.
*
* @param destKeyStream location to write out the destination, PrivateKey, and SigningPrivateKey,
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
*/
public Destination createDestination(OutputStream destKeyStream, Certificate cert) throws I2PException, IOException {
Destination d = new Destination();
d.setCertificate(cert);
Object keypair[] = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey publicKey = (PublicKey) keypair[0];
PrivateKey privateKey = (PrivateKey) keypair[1];
Object signingKeys[] = KeyGenerator.getInstance().generateSigningKeypair();
SimpleDataStructure signingKeys[];
if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
KeyCertificate kcert = cert.toKeyCertificate();
SigType type = kcert.getSigType();
try {
signingKeys = KeyGenerator.getInstance().generateSigningKeys(type);
} catch (GeneralSecurityException gse) {
throw new I2PException("keygen fail", gse);
}
} else {
signingKeys = KeyGenerator.getInstance().generateSigningKeys();
}
SigningPublicKey signingPubKey = (SigningPublicKey) signingKeys[0];
SigningPrivateKey signingPrivKey = (SigningPrivateKey) signingKeys[1];
d.setPublicKey(publicKey);
d.setSigningPublicKey(signingPubKey);
if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
// fix up key certificate or padding
KeyCertificate kcert = cert.toKeyCertificate();
SigType type = kcert.getSigType();
int len = type.getPubkeyLen();
if (len < 128) {
byte[] pad = new byte[128 - len];
RandomSource.getInstance().nextBytes(pad);
d.setPadding(pad);
} else if (len > 128) {
System.arraycopy(signingPubKey.getData(), 128, kcert.getPayload(), KeyCertificate.HEADER_LENGTH, len - 128);
}
}
d.setCertificate(cert);
d.writeBytes(destKeyStream);
privateKey.writeBytes(destKeyStream);

View File

@ -67,7 +67,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
/** private key for decryption */
private final PrivateKey _privateKey;
/** private key for signing */
private final SigningPrivateKey _signingPrivateKey;
private /* final */ SigningPrivateKey _signingPrivateKey;
/** configuration options */
private final Properties _options;
/** this session's Id */
@ -390,6 +390,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
private void readDestination(InputStream destKeyStream) throws DataFormatException, IOException {
_myDestination.readBytes(destKeyStream);
_privateKey.readBytes(destKeyStream);
_signingPrivateKey = new SigningPrivateKey(_myDestination.getSigningPublicKey().getType());
_signingPrivateKey.readBytes(destKeyStream);
}

View File

@ -12,6 +12,7 @@ import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.crypto.SigType;
import net.i2p.data.Certificate;
import net.i2p.data.Destination;
@ -20,14 +21,30 @@ import net.i2p.data.Destination;
* just used to talk to the router.
*/
public class I2PSimpleClient implements I2PClient {
/** @deprecated Don't do this */
/**
* @deprecated Don't do this
* @throws UnsupportedOperationException always
*/
public Destination createDestination(OutputStream destKeyStream) throws I2PException, IOException {
return null;
throw new UnsupportedOperationException();
}
/** @deprecated or this */
/**
* @deprecated Don't do this
* @throws UnsupportedOperationException always
* @since 0.9.12
*/
public Destination createDestination(OutputStream destKeyStream, SigType type) throws I2PException, IOException {
throw new UnsupportedOperationException();
}
/**
* @deprecated Don't do this
* @throws UnsupportedOperationException always
*/
public Destination createDestination(OutputStream destKeyStream, Certificate cert) throws I2PException, IOException {
return null;
throw new UnsupportedOperationException();
}
/**
@ -37,6 +54,7 @@ public class I2PSimpleClient implements I2PClient {
public I2PSession createSession(InputStream destKeyStream, Properties options) throws I2PSessionException {
return createSession(I2PAppContext.getGlobalContext(), options);
}
/**
* Create a new session (though do not connect it yet)
*

View File

@ -14,6 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext;
import net.i2p.crypto.KeyGenerator;
import net.i2p.crypto.SigType;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
@ -105,6 +106,15 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
}
try {
leaseSet.sign(session.getPrivateKey());
// Workaround for unparsable serialized signing private key for revocation
// Send him a dummy DSA_SHA1 private key since it's unused anyway
// See CreateLeaseSetMessage.doReadMessage()
SigningPrivateKey spk = li.getSigningPrivateKey();
if (!_context.isRouterContext() && spk.getType() != SigType.DSA_SHA1) {
byte[] dummy = new byte[SigningPrivateKey.KEYSIZE_BYTES];
_context.random().nextBytes(dummy);
spk = new SigningPrivateKey(dummy);
}
session.getProducer().createLeaseSet(session, leaseSet, li.getSigningPrivateKey(), li.getPrivateKey());
session.setLeaseSet(leaseSet);
} catch (DataFormatException dfe) {

View File

@ -14,6 +14,7 @@ import java.io.IOException;
import net.i2p.I2PAppContext;
import net.i2p.crypto.DSAEngine;
import net.i2p.crypto.SHA256Generator;
import net.i2p.crypto.SigType;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
@ -67,7 +68,10 @@ public final class I2PDatagramDissector {
try {
// read destination
rxDest = Destination.create(dgStream);
rxSign = new Signature();
SigType type = rxDest.getSigningPublicKey().getType();
if (type == null)
throw new DataFormatException("unsupported sig type");
rxSign = new Signature(type);
// read signature
rxSign.readBytes(dgStream);

View File

@ -89,13 +89,20 @@ public class DSAEngine {
* Uses TheCrypto code for DSA-SHA1 unless configured to use the java.security libraries.
*/
public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) {
return verifySignature(signature, signedData, 0, signedData.length, verifyingKey);
}
/**
* Verify using any sig type as of 0.9.12 (DSA only prior to that)
*/
public boolean verifySignature(Signature signature, byte signedData[], int offset, int size, SigningPublicKey verifyingKey) {
boolean rv;
SigType type = signature.getType();
if (type != verifyingKey.getType())
throw new IllegalArgumentException("type mismatch sig=" + signature.getType() + " key=" + verifyingKey.getType());
if (type != SigType.DSA_SHA1) {
try {
rv = altVerifySig(signature, signedData, verifyingKey);
rv = altVerifySig(signature, signedData, offset, size, verifyingKey);
if ((!rv) && _log.shouldLog(Log.WARN))
_log.warn(type + " Sig Verify Fail");
return rv;
@ -107,7 +114,7 @@ public class DSAEngine {
}
if (_useJavaLibs) {
try {
rv = altVerifySigSHA1(signature, signedData, verifyingKey);
rv = altVerifySigSHA1(signature, signedData, offset, size, verifyingKey);
if ((!rv) && _log.shouldLog(Log.WARN))
_log.warn("Lib DSA Sig Verify Fail");
return rv;
@ -117,19 +124,12 @@ public class DSAEngine {
// now try TheCrypto
}
}
rv = verifySignature(signature, signedData, 0, signedData.length, verifyingKey);
rv = verifySignature(signature, calculateHash(signedData, offset, size), verifyingKey);
if ((!rv) && _log.shouldLog(Log.WARN))
_log.warn("TheCrypto DSA Sig Verify Fail");
return rv;
}
/**
* Verify using DSA-SHA1 ONLY
*/
public boolean verifySignature(Signature signature, byte signedData[], int offset, int size, SigningPublicKey verifyingKey) {
return verifySignature(signature, calculateHash(signedData, offset, size), verifyingKey);
}
/**
* Verify using DSA-SHA1 ONLY
*/
@ -256,16 +256,26 @@ public class DSAEngine {
}
/**
* Sign using DSA-SHA1 or ECDSA.
* Sign using any key type.
* Uses TheCrypto code unless configured to use the java.security libraries.
*
* @return null on error
*/
public Signature sign(byte data[], SigningPrivateKey signingKey) {
return sign(data, 0, data.length, signingKey);
}
/**
* Sign using any key type as of 0.9.12 (DSA-SHA1 only prior to that)
*
* @return null on error
*/
public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) {
if ((signingKey == null) || (data == null) || (data.length <= 0)) return null;
SigType type = signingKey.getType();
if (type != SigType.DSA_SHA1) {
try {
return altSign(data, signingKey);
return altSign(data, offset, length, signingKey);
} catch (GeneralSecurityException gse) {
if (_log.shouldLog(Log.WARN))
_log.warn(type + " Sign Fail", gse);
@ -274,23 +284,13 @@ public class DSAEngine {
}
if (_useJavaLibs) {
try {
return altSignSHA1(data, signingKey);
return altSignSHA1(data, offset, length, signingKey);
} catch (GeneralSecurityException gse) {
if (_log.shouldLog(Log.WARN))
_log.warn("Lib Sign Fail, privkey = " + signingKey, gse);
// now try TheCrypto
}
}
return sign(data, 0, data.length, signingKey);
}
/**
* Sign using DSA-SHA1 ONLY
*
* @return null on error
*/
public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) {
if ((signingKey == null) || (data == null) || (data.length <= 0)) return null;
SHA1Hash h = calculateHash(data, offset, length);
return sign(h, signingKey);
}
@ -495,20 +495,20 @@ public class DSAEngine {
/**
* Generic verify DSA_SHA1, ECDSA, or RSA
* @throws GeneralSecurityException if algorithm unvailable or on other errors
* @since 0.9.9
* @since 0.9.9 added off/len 0.9.12
*/
private boolean altVerifySig(Signature signature, byte[] data, SigningPublicKey verifyingKey)
private boolean altVerifySig(Signature signature, byte[] data, int offset, int len, SigningPublicKey verifyingKey)
throws GeneralSecurityException {
SigType type = signature.getType();
if (type != verifyingKey.getType())
throw new IllegalArgumentException("type mismatch sig=" + type + " key=" + verifyingKey.getType());
if (type == SigType.DSA_SHA1)
return altVerifySigSHA1(signature, data, verifyingKey);
return altVerifySigSHA1(signature, data, offset, len, verifyingKey);
java.security.Signature jsig = java.security.Signature.getInstance(type.getAlgorithmName());
PublicKey pubKey = SigUtil.toJavaKey(verifyingKey);
jsig.initVerify(pubKey);
jsig.update(data);
jsig.update(data, offset, len);
boolean rv = jsig.verify(SigUtil.toJavaSig(signature));
return rv;
}
@ -555,13 +555,14 @@ public class DSAEngine {
/**
* Alternate to verifySignature() using java.security libraries.
* @throws GeneralSecurityException if algorithm unvailable or on other errors
* @since 0.8.7
* @since 0.8.7 added off/len 0.9.12
*/
private boolean altVerifySigSHA1(Signature signature, byte[] data, SigningPublicKey verifyingKey) throws GeneralSecurityException {
private boolean altVerifySigSHA1(Signature signature, byte[] data, int offset,
int len, SigningPublicKey verifyingKey) throws GeneralSecurityException {
java.security.Signature jsig = java.security.Signature.getInstance("SHA1withDSA");
PublicKey pubKey = SigUtil.toJavaDSAKey(verifyingKey);
jsig.initVerify(pubKey);
jsig.update(data);
jsig.update(data, offset, len);
boolean rv = jsig.verify(SigUtil.toJavaSig(signature));
//if (!rv) {
// System.out.println("BAD SIG\n" + net.i2p.util.HexDump.dump(signature.getData()));
@ -573,17 +574,18 @@ public class DSAEngine {
/**
* Generic sign DSA_SHA1, ECDSA, or RSA
* @throws GeneralSecurityException if algorithm unvailable or on other errors
* @since 0.9.9
* @since 0.9.9 added off/len 0.9.12
*/
private Signature altSign(byte[] data, SigningPrivateKey privateKey) throws GeneralSecurityException {
private Signature altSign(byte[] data, int offset, int len,
SigningPrivateKey privateKey) throws GeneralSecurityException {
SigType type = privateKey.getType();
if (type == SigType.DSA_SHA1)
return altSignSHA1(data, privateKey);
return altSignSHA1(data, offset, len, privateKey);
java.security.Signature jsig = java.security.Signature.getInstance(type.getAlgorithmName());
PrivateKey privKey = SigUtil.toJavaKey(privateKey);
jsig.initSign(privKey, _context.random());
jsig.update(data);
jsig.update(data, offset, len);
return SigUtil.fromJavaSig(jsig.sign(), type);
}
@ -622,13 +624,14 @@ public class DSAEngine {
/**
* Alternate to sign() using java.security libraries.
* @throws GeneralSecurityException if algorithm unvailable or on other errors
* @since 0.8.7
* @since 0.8.7 added off/len args 0.9.12
*/
private Signature altSignSHA1(byte[] data, SigningPrivateKey privateKey) throws GeneralSecurityException {
private Signature altSignSHA1(byte[] data, int offset, int len,
SigningPrivateKey privateKey) throws GeneralSecurityException {
java.security.Signature jsig = java.security.Signature.getInstance("SHA1withDSA");
PrivateKey privKey = SigUtil.toJavaDSAKey(privateKey);
jsig.initSign(privKey, _context.random());
jsig.update(data);
jsig.update(data, offset, len);
return SigUtil.fromJavaSig(jsig.sign(), SigType.DSA_SHA1);
}

View File

@ -530,23 +530,6 @@ public class SU3File {
return buf.toString();
}
/**
* @param stype number or name
* @return null if not found
* @since 0.9.9
*/
private static SigType parseSigType(String stype) {
try {
return SigType.valueOf(stype.toUpperCase(Locale.US));
} catch (IllegalArgumentException iae) {
try {
int code = Integer.parseInt(stype);
return SigType.getByCode(code);
} catch (NumberFormatException nfe) {
return null;
}
}
}
/**
* @param stype number or name
* @return null if not found
@ -639,7 +622,7 @@ public class SU3File {
*/
private static final boolean signCLI(String stype, String ctype, String inputFile, String signedFile,
String privateKeyFile, String version, String signerName, String keypw) {
SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : parseSigType(stype);
SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : SigType.parseSigType(stype);
if (type == null) {
System.out.println("Signature type " + stype + " is not supported");
return false;
@ -731,7 +714,7 @@ public class SU3File {
* @since 0.9.9
*/
private static final boolean genKeysCLI(String stype, String publicKeyFile, String privateKeyFile, String alias) {
SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : parseSigType(stype);
SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : SigType.parseSigType(stype);
if (type == null) {
System.out.println("Signature type " + stype + " is not supported");
return false;

View File

@ -5,6 +5,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import net.i2p.data.Hash;
@ -170,4 +171,24 @@ public enum SigType {
public static SigType getByCode(int code) {
return BY_CODE.get(Integer.valueOf(code));
}
/**
* Convenience for user apps
*
* @param stype number or name
* @return null if not found
* @since 0.9.9 moved from SU3File in 0.9.12
*/
public static SigType parseSigType(String stype) {
try {
return valueOf(stype.toUpperCase(Locale.US));
} catch (IllegalArgumentException iae) {
try {
int code = Integer.parseInt(stype);
return getByCode(code);
} catch (NumberFormatException nfe) {
return null;
}
}
}
}

View File

@ -42,6 +42,8 @@ public class Certificate extends DataStructureImpl {
public final static int CERTIFICATE_LENGTH_SIGNED_WITH_HASH = Signature.SIGNATURE_BYTES + Hash.HASH_LENGTH;
/** Contains multiple certs */
public final static int CERTIFICATE_TYPE_MULTIPLE = 4;
/** @since 0.9.12 */
public final static int CERTIFICATE_TYPE_KEY = 5;
/**
* If null cert, return immutable static instance, else create new
@ -58,6 +60,13 @@ public class Certificate extends DataStructureImpl {
return new Certificate(type, null);
byte[] payload = new byte[length];
System.arraycopy(data, off + 3, payload, 0, length);
if (type == CERTIFICATE_TYPE_KEY) {
try {
return new KeyCertificate(payload);
} catch (DataFormatException dfe) {
throw new IllegalArgumentException(dfe);
}
}
return new Certificate(type, payload);
}
@ -77,13 +86,20 @@ public class Certificate extends DataStructureImpl {
int read = DataHelper.read(in, payload);
if (read != length)
throw new DataFormatException("Not enough bytes for the payload (read: " + read + " length: " + length + ')');
if (type == CERTIFICATE_TYPE_KEY)
return new KeyCertificate(payload);
return new Certificate(type, payload);
}
public Certificate() {
}
/**
* @throws IllegalArgumentException if type < 0
*/
public Certificate(int type, byte[] payload) {
if (type < 0)
throw new IllegalArgumentException();
_type = type;
_payload = payload;
}
@ -93,7 +109,15 @@ public class Certificate extends DataStructureImpl {
return _type;
}
/**
* @throws IllegalArgumentException if type < 0
* @throws IllegalStateException if already set
*/
public void setCertificateType(int type) {
if (type < 0)
throw new IllegalArgumentException();
if (_type != 0 && _type != type)
throw new IllegalStateException("already set");
_type = type;
}
@ -101,11 +125,21 @@ public class Certificate extends DataStructureImpl {
return _payload;
}
/**
* @throws IllegalStateException if already set
*/
public void setPayload(byte[] payload) {
if (_payload != null)
throw new IllegalStateException("already set");
_payload = payload;
}
/**
* @throws IllegalStateException if already set
*/
public void readBytes(InputStream in) throws DataFormatException, IOException {
if (_type != 0 || _payload != null)
throw new IllegalStateException("already set");
_type = (int) DataHelper.readLong(in, 1);
int length = (int) DataHelper.readLong(in, 2);
if (length > 0) {
@ -149,7 +183,12 @@ public class Certificate extends DataStructureImpl {
return cur - offset;
}
/**
* @throws IllegalStateException if already set
*/
public int readBytes(byte source[], int offset) throws DataFormatException {
if (_type != 0 || _payload != null)
throw new IllegalStateException("already set");
if (source == null) throw new DataFormatException("Cert is null");
if (source.length < offset + 3)
throw new DataFormatException("Cert is too small [" + source.length + " off=" + offset + "]");
@ -175,6 +214,18 @@ public class Certificate extends DataStructureImpl {
return 1 + 2 + (_payload != null ? _payload.length : 0);
}
/**
* Up-convert this to a KeyCertificate
*
* @throws DataFormatException if cert type != CERTIFICATE_TYPE_KEY
* @since 0.9.12
*/
public KeyCertificate toKeyCertificate() throws DataFormatException {
if (_type != CERTIFICATE_TYPE_KEY)
throw new DataFormatException("type");
return new KeyCertificate(this);
}
@Override
public boolean equals(Object object) {
if (object == this) return true;
@ -194,6 +245,8 @@ public class Certificate extends DataStructureImpl {
buf.append("[Certificate: type: ");
if (getCertificateType() == CERTIFICATE_TYPE_NULL)
buf.append("Null certificate");
else if (getCertificateType() == CERTIFICATE_TYPE_KEY)
buf.append("Key certificate");
else if (getCertificateType() == CERTIFICATE_TYPE_HASHCASH)
buf.append("Hashcash certificate");
else if (getCertificateType() == CERTIFICATE_TYPE_HIDDEN)

View File

@ -57,6 +57,16 @@ public class Destination extends KeysAndCert {
PublicKey pk = PublicKey.create(in);
SigningPublicKey sk = SigningPublicKey.create(in);
Certificate c = Certificate.create(in);
byte[] padding;
if (c.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
// convert SPK to new SPK and padding
KeyCertificate kcert = c.toKeyCertificate();
padding = sk.getPadding(kcert);
sk = sk.toTypedKey(kcert);
c = kcert;
} else {
padding = null;
}
Destination rv;
synchronized(_cache) {
rv = _cache.get(sk);
@ -67,7 +77,7 @@ public class Destination extends KeysAndCert {
}
//if (STATS)
// I2PAppContext.getGlobalContext().statManager().addRateData("DestCache", 0);
rv = new Destination(pk, sk, c);
rv = new Destination(pk, sk, c, padding);
_cache.put(sk, rv);
}
return rv;
@ -86,10 +96,11 @@ public class Destination extends KeysAndCert {
/**
* @since 0.9.9
*/
private Destination(PublicKey pk, SigningPublicKey sk, Certificate c) {
private Destination(PublicKey pk, SigningPublicKey sk, Certificate c, byte[] padding) {
_publicKey = pk;
_signingKey = sk;
_certificate = c;
_padding = padding;
}
/**
@ -100,14 +111,19 @@ public class Destination extends KeysAndCert {
int cur = offset;
System.arraycopy(_publicKey.getData(), 0, target, cur, PublicKey.KEYSIZE_BYTES);
cur += PublicKey.KEYSIZE_BYTES;
System.arraycopy(_signingKey.getData(), 0, target, cur, SigningPublicKey.KEYSIZE_BYTES);
cur += SigningPublicKey.KEYSIZE_BYTES;
if (_padding != null) {
System.arraycopy(_padding, 0, target, cur, _padding.length);
cur += _padding.length;
}
System.arraycopy(_signingKey.getData(), 0, target, cur, _signingKey.length());
cur += _signingKey.length();
cur += _certificate.writeBytes(target, cur);
return cur - offset;
}
/**
* @deprecated was used only by Packet.java in streaming, now unused
* deprecated was used only by Packet.java in streaming, now unused
* Warning - used by i2p-bote. Does NOT support alternate key types. DSA-SHA1 only.
*
* @throws IllegalStateException if data already set
*/
@ -132,7 +148,16 @@ public class Destination extends KeysAndCert {
}
public int size() {
return PublicKey.KEYSIZE_BYTES + SigningPublicKey.KEYSIZE_BYTES + _certificate.size();
int rv = PublicKey.KEYSIZE_BYTES + _signingKey.length();
if (_certificate.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
// cert data included in keys
rv += 7;
if (_padding != null)
rv += _padding.length;
} else {
rv += _certificate.size();
}
return rv;
}
/**

View File

@ -0,0 +1,252 @@
package net.i2p.data;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import net.i2p.crypto.SigType;
/**
* This certificate type gets its own class because it's going to be used a lot.
*
* The crypto type is assumed to be always 0x0000 (ElG) for now.
*
* @since 0.9.12
*/
public class KeyCertificate extends Certificate {
public static final int HEADER_LENGTH = 4;
public static final KeyCertificate ELG_ECDSA256_CERT;
static {
KeyCertificate kc;
try {
kc = new ECDSA256Cert();
} catch (DataFormatException dfe) {
kc = null; // won't happen
}
ELG_ECDSA256_CERT = kc;
}
/**
* @param payload 4 bytes minimum if non-null
* @throws DataFormatException
*/
public KeyCertificate(byte[] payload) throws DataFormatException {
super(CERTIFICATE_TYPE_KEY, payload);
if (payload != null && payload.length < HEADER_LENGTH)
throw new DataFormatException("data");
}
/**
* A KeyCertificate with crypto type 0 (ElGamal)
* and the signature type and extra data from the given public key.
*
* @param sig non-null data non-null
* @throws IllegalArgumentException
*/
public KeyCertificate(SigningPublicKey spk) {
super(CERTIFICATE_TYPE_KEY, null);
if (spk == null || spk.getData() == null)
throw new IllegalArgumentException();
SigType type = spk.getType();
int len = type.getPubkeyLen();
int extra = Math.max(0, len - 128);
_payload = new byte[HEADER_LENGTH + extra];
int code = type.getCode();
_payload[0] = (byte) (code >> 8);
_payload[1] = (byte) (code & 0xff);
// 2 and 3 always 0, it is the only crypto code for now
if (extra > 0)
System.arraycopy(spk.getData(), 128, _payload, HEADER_LENGTH, extra);
}
/**
* A KeyCertificate with crypto type 0 (ElGamal)
* and the signature type as specified.
* Payload is created.
* If type.getPubkeyLen() is greater than 128, caller MUST
* fill in the extra key data in the payload.
*
* @param sig non-null data non-null
* @throws IllegalArgumentException
*/
public KeyCertificate(SigType type) {
super(CERTIFICATE_TYPE_KEY, null);
int len = type.getPubkeyLen();
int extra = Math.max(0, len - 128);
_payload = new byte[HEADER_LENGTH + extra];
int code = type.getCode();
_payload[0] = (byte) (code >> 8);
_payload[1] = (byte) (code & 0xff);
// 2 and 3 always 0, it is the only crypto code for now
}
/**
* Up-convert a cert to this class
*
* @param cert payload 4 bytes minimum if non-null
* @throws DataFormatException if cert type != CERTIFICATE_TYPE_KEY
*/
public KeyCertificate(Certificate cert) throws DataFormatException {
this(cert.getPayload());
if (cert.getCertificateType() != CERTIFICATE_TYPE_KEY)
throw new DataFormatException("type");
}
/**
* @return -1 if unset
*/
public int getSigTypeCode() {
if (_payload == null)
return -1;
return ((_payload[0] & 0xff) << 8) | (_payload[1] & 0xff);
}
/**
* @return -1 if unset
*/
public int getCryptoTypeCode() {
if (_payload == null)
return -1;
return ((_payload[2] & 0xff) << 8) | (_payload[3] & 0xff);
}
/**
* @return null if unset or unknown
*/
public SigType getSigType() {
return SigType.getByCode(getSigTypeCode());
}
/**
* Signing Key extra data, if any, is first in the array.
* Crypto Key extra data, if any, is second in the array,
* at offset max(0, 128 - getSigType().getPubkeyLen()
*
* @return null if unset or none
*/
public byte[] getExtraKeyData() {
if (_payload == null || _payload.length <= HEADER_LENGTH)
return null;
byte[] rv = new byte[_payload.length - HEADER_LENGTH];
System.arraycopy(_payload, HEADER_LENGTH, rv, 0, rv.length);
return rv;
}
/**
* Signing Key extra data, if any.
*
* @return null if unset or none
* @throws UnsupportedOperationException if the sig type is unsupported
*/
public byte[] getExtraSigningKeyData() {
// we assume no crypto key data
if (_payload == null || _payload.length <= HEADER_LENGTH)
return null;
SigType type = getSigType();
if (type == null)
throw new UnsupportedOperationException("unknown sig type");
int extra = 128 - type.getPubkeyLen();
if (_payload.length == HEADER_LENGTH + extra)
return getExtraKeyData();
byte[] rv = new byte[extra];
System.arraycopy(_payload, HEADER_LENGTH, rv, 0, extra);
return rv;
}
// todo
// constructor w/ crypto type
// getCryptoType()
// getCryptoDataOffset()
@Override
public KeyCertificate toKeyCertificate() {
return this;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(64);
buf.append("[Certificate: type: Key certificate");
if (_payload == null) {
buf.append(" null payload");
} else {
buf.append("\n\tCrypto type: ").append(getCryptoTypeCode());
buf.append("\n\tSig type: ").append(getSigTypeCode())
.append(" (").append(getSigType()).append(')');
if (_payload.length > HEADER_LENGTH)
buf.append("\n\tKey data: ").append(_payload.length - HEADER_LENGTH).append(" bytes");
}
buf.append("]");
return buf.toString();
}
/**
* An immutable ElG/ECDSA-256 certificate.
* @since 0.8.3
*/
private static final class ECDSA256Cert extends KeyCertificate {
private static final byte[] ECDSA256_DATA = new byte[] {
CERTIFICATE_TYPE_KEY, 0, HEADER_LENGTH, 0, (byte) (SigType.ECDSA_SHA256_P256.getCode()), 0, 0
};
private static final int ECDSA256_LENGTH = ECDSA256_DATA.length;
private static final byte[] ECDSA256_PAYLOAD = new byte[] {
0, (byte) (SigType.ECDSA_SHA256_P256.getCode()), 0, 0
};
public ECDSA256Cert() throws DataFormatException {
super(ECDSA256_PAYLOAD);
}
/** @throws RuntimeException always */
@Override
public void setCertificateType(int type) {
throw new RuntimeException("Data already set");
}
/** @throws RuntimeException always */
@Override
public void setPayload(byte[] payload) {
throw new RuntimeException("Data already set");
}
/** @throws RuntimeException always */
@Override
public void readBytes(InputStream in) throws DataFormatException, IOException {
throw new RuntimeException("Data already set");
}
/** Overridden for efficiency */
@Override
public void writeBytes(OutputStream out) throws IOException {
out.write(ECDSA256_DATA);
}
/** Overridden for efficiency */
@Override
public int writeBytes(byte target[], int offset) {
System.arraycopy(ECDSA256_DATA, 0, target, offset, ECDSA256_LENGTH);
return ECDSA256_LENGTH;
}
/** @throws RuntimeException always */
@Override
public int readBytes(byte source[], int offset) throws DataFormatException {
throw new RuntimeException("Data already set");
}
/** Overridden for efficiency */
@Override
public int size() {
return ECDSA256_LENGTH;
}
/** Overridden for efficiency */
@Override
public int hashCode() {
return 1234567;
}
}
}

View File

@ -35,6 +35,7 @@ public class KeysAndCert extends DataStructureImpl {
protected SigningPublicKey _signingKey;
protected Certificate _certificate;
protected Hash __calculatedHash;
protected byte[] _padding;
public Certificate getCertificate() {
return _certificate;
@ -78,6 +79,17 @@ public class KeysAndCert extends DataStructureImpl {
__calculatedHash = null;
}
/**
* @throws IllegalStateException if was already set
* @since 0.9.12
*/
public void setPadding(byte[] padding) {
if (_padding != null)
throw new IllegalStateException();
_padding = padding;
__calculatedHash = null;
}
/**
* @throws IllegalStateException if data already set
*/
@ -85,8 +97,18 @@ public class KeysAndCert extends DataStructureImpl {
if (_publicKey != null || _signingKey != null || _certificate != null)
throw new IllegalStateException();
_publicKey = PublicKey.create(in);
_signingKey = SigningPublicKey.create(in);
_certificate = Certificate.create(in);
SigningPublicKey spk = SigningPublicKey.create(in);
Certificate cert = Certificate.create(in);
if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
// convert SPK to new SPK and padding
KeyCertificate kcert = cert.toKeyCertificate();
_signingKey = spk.toTypedKey(kcert);
_padding = spk.getPadding(kcert);
_certificate = kcert;
} else {
_signingKey = spk;
_certificate = cert;
}
__calculatedHash = null;
}
@ -94,7 +116,9 @@ public class KeysAndCert extends DataStructureImpl {
if ((_certificate == null) || (_publicKey == null) || (_signingKey == null))
throw new DataFormatException("Not enough data to format the router identity");
_publicKey.writeBytes(out);
_signingKey.writeBytes(out);
if (_padding != null)
out.write(_padding);
_signingKey.writeTruncatedBytes(out);
_certificate.writeBytes(out);
}
@ -106,6 +130,7 @@ public class KeysAndCert extends DataStructureImpl {
return
DataHelper.eq(_signingKey, ident._signingKey)
&& DataHelper.eq(_publicKey, ident._publicKey)
&& DataHelper.eq(_padding, ident._padding)
&& DataHelper.eq(_certificate, ident._certificate);
}
@ -125,6 +150,8 @@ public class KeysAndCert extends DataStructureImpl {
buf.append("\n\tCertificate: ").append(_certificate);
buf.append("\n\tPublicKey: ").append(_publicKey);
buf.append("\n\tSigningPublicKey: ").append(_signingKey);
if (_padding != null)
buf.append("\n\tPadding: ").append(_padding.length).append(" bytes");
buf.append(']');
return buf.toString();
}

View File

@ -275,11 +275,9 @@ public class LeaseSet extends DatabaseEntry {
protected byte[] getBytes() {
if ((_destination == null) || (_encryptionKey == null) || (_signingKey == null))
return null;
int len = PublicKey.KEYSIZE_BYTES // dest
+ SigningPublicKey.KEYSIZE_BYTES // dest
+ 3 // cert minimum, could be more, only used to size the BAOS
int len = _destination.size()
+ PublicKey.KEYSIZE_BYTES // encryptionKey
+ SigningPublicKey.KEYSIZE_BYTES // signingKey
+ _signingKey.length() // signingKey
+ 1
+ _leases.size() * 44; // leases
ByteArrayOutputStream out = new ByteArrayOutputStream(len);
@ -310,7 +308,9 @@ public class LeaseSet extends DatabaseEntry {
throw new IllegalStateException();
_destination = Destination.create(in);
_encryptionKey = PublicKey.create(in);
_signingKey = SigningPublicKey.create(in);
// revocation signing key must be same type as the destination signing key
_signingKey = new SigningPublicKey(_destination.getSigningPublicKey().getType());
_signingKey.readBytes(in);
int numLeases = (int) DataHelper.readLong(in, 1);
if (numLeases > MAX_LEASES)
throw new DataFormatException("Too many leases - max is " + MAX_LEASES);
@ -320,7 +320,8 @@ public class LeaseSet extends DatabaseEntry {
lease.readBytes(in);
addLease(lease);
}
_signature = new Signature();
// signature must be same type as the destination signing key
_signature = new Signature(_destination.getSigningPublicKey().getType());
_signature.readBytes(in);
}
@ -345,11 +346,9 @@ public class LeaseSet extends DatabaseEntry {
* Number of bytes, NOT including signature
*/
public int size() {
return PublicKey.KEYSIZE_BYTES //destination.pubKey
+ SigningPublicKey.KEYSIZE_BYTES // destination.signPubKey
+ _destination.getCertificate().size() // destination.certificate, usually 3
return _destination.size()
+ PublicKey.KEYSIZE_BYTES // encryptionKey
+ SigningPublicKey.KEYSIZE_BYTES // signingKey
+ _signingKey.length() // signingKey
+ 1 // number of leases
+ _leases.size() * (Hash.HASH_LENGTH + 4 + 8);
}

View File

@ -6,6 +6,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
@ -19,7 +21,9 @@ import net.i2p.client.I2PClientFactory;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.crypto.DSAEngine;
import net.i2p.crypto.KeyGenerator;
import net.i2p.crypto.SigType;
import net.i2p.util.RandomSource;
/**
* This helper class reads and writes files in the
@ -138,11 +142,15 @@ public class PrivateKeyFile {
PrivateKeyFile pkf2 = new PrivateKeyFile(args[g.getOptind() + 1]);
pkf.setSignedCert(pkf2);
System.out.println("New destination with signed cert is:");
break;
case 't':
// TODO merge with ecdsa branch
throw new UnsupportedOperationException();
// KeyCert
SigType type = SigType.parseSigType(args[g.getOptind()]);
if (type == null)
throw new IllegalArgumentException("Signature type " + args[g.getOptind()] + " is not supported");
pkf.setKeyCert(type);
System.out.println("New destination with key cert is:");
break;
default:
// shouldn't happen
@ -151,7 +159,7 @@ public class PrivateKeyFile {
}
System.out.println(pkf);
pkf.write();
verifySignature(d);
verifySignature(pkf.getDestination());
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
@ -268,6 +276,43 @@ public class PrivateKeyFile {
return c;
}
/**
* Change cert type - caller must also call write().
* Side effect - creates new Destination object.
* @since 0.9.12
*/
public Certificate setKeyCert(SigType type) {
if (type == SigType.DSA_SHA1)
return setCertType(Certificate.CERTIFICATE_TYPE_NULL);
if (dest == null)
throw new IllegalArgumentException("Dest is null");
KeyCertificate c = new KeyCertificate(type);
SimpleDataStructure signingKeys[];
try {
signingKeys = KeyGenerator.getInstance().generateSigningKeys(type);
} catch (GeneralSecurityException gse) {
throw new RuntimeException("keygen fail", gse);
}
SigningPublicKey signingPubKey = (SigningPublicKey) signingKeys[0];
signingPrivKey = (SigningPrivateKey) signingKeys[1];
// dests now immutable, must create new
Destination newdest = new Destination();
newdest.setPublicKey(dest.getPublicKey());
newdest.setSigningPublicKey(signingPubKey);
// fix up key certificate or padding
int len = type.getPubkeyLen();
if (len < 128) {
byte[] pad = new byte[128 - len];
RandomSource.getInstance().nextBytes(pad);
newdest.setPadding(pad);
} else if (len > 128) {
System.arraycopy(signingPubKey.getData(), 128, c.getPayload(), KeyCertificate.HEADER_LENGTH, len - 128);
}
newdest.setCertificate(c);
dest = newdest;
return c;
}
/** change to hashcash cert - caller must also call write() */
public Certificate setHashCashCert(int effort) {
Certificate c = setCertType(Certificate.CERTIFICATE_TYPE_HASHCASH);
@ -503,8 +548,6 @@ public class PrivateKeyFile {
private static final int HASH_EFFORT = VerifiedDestination.MIN_HASHCASH_EFFORT;
private final File file;
private final I2PClient client;
private Destination dest;

View File

@ -554,7 +554,7 @@ public class RouterInfo extends DatabaseEntry {
}
}
DataHelper.readProperties(din, _options);
_signature = new Signature();
_signature = new Signature(_identity.getSigningPublicKey().getType());
_signature.readBytes(in);
if (verifySig) {

View File

@ -13,12 +13,15 @@ import net.i2p.crypto.SigType;
/**
* Defines the signature as defined by the I2P data structure spec.
* A signature is a 40-byte array verifying the authenticity of some data
* By default, a signature is a 40-byte array verifying the authenticity of some data
* using the DSA-SHA1 algorithm.
*
* The signature is the 20-byte R followed by the 20-byte S,
* both are unsigned integers.
*
* As of release 0.9.8, signatures of arbitrary length and type are supported.
* See SigType.
*
* @author jrandom
*/
public class Signature extends SimpleDataStructure {
@ -39,10 +42,15 @@ public class Signature extends SimpleDataStructure {
}
/**
* Unknown type not allowed as we won't know the length to read in the data.
*
* @param type non-null
* @since 0.9.8
*/
public Signature(SigType type) {
super();
if (type == null)
throw new IllegalArgumentException("unknown type");
_type = type;
}
@ -51,10 +59,15 @@ public class Signature extends SimpleDataStructure {
}
/**
* Should we allow an unknown type here?
*
* @param type non-null
* @since 0.9.8
*/
public Signature(SigType type, byte data[]) {
super();
if (type == null)
throw new IllegalArgumentException("unknown type");
_type = type;
setData(data);
}
@ -64,6 +77,7 @@ public class Signature extends SimpleDataStructure {
}
/**
* @return non-null
* @since 0.9.8
*/
public SigType getType() {

View File

@ -14,10 +14,13 @@ import net.i2p.crypto.SigType;
/**
* Defines the SigningPrivateKey as defined by the I2P data structure spec.
* A signing private key is 20 byte Integer. The private key represents only the
* A signing private key is by default a 20 byte Integer. The private key represents only the
* exponent, not the primes, which are constant and defined in the crypto spec.
* This key varies from the PrivateKey in its usage (signing, not decrypting)
*
* As of release 0.9.8, keys of arbitrary length and type are supported.
* See SigType.
*
* @author jrandom
*/
public class SigningPrivateKey extends SimpleDataStructure {

View File

@ -11,15 +11,19 @@ package net.i2p.data;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import net.i2p.crypto.SigType;
/**
* Defines the SigningPublicKey as defined by the I2P data structure spec.
* A signing public key is 128 byte Integer. The public key represents only the
* A signing public key is by default 128 byte Integer. The public key represents only the
* exponent, not the primes, which are constant and defined in the crypto spec.
* This key varies from the PrivateKey in its usage (verifying signatures, not encrypting)
*
* As of release 0.9.8, keys of arbitrary length and type are supported.
* See SigType.
*
* @author jrandom
*/
public class SigningPublicKey extends SimpleDataStructure {
@ -55,6 +59,7 @@ public class SigningPublicKey extends SimpleDataStructure {
}
/**
* @param type if null, type is unknown
* @since 0.9.8
*/
public SigningPublicKey(SigType type) {
@ -67,12 +72,16 @@ public class SigningPublicKey extends SimpleDataStructure {
}
/**
* @param type if null, type is unknown
* @since 0.9.8
*/
public SigningPublicKey(SigType type, byte data[]) {
super();
_type = type;
setData(data);
if (type != null || data == null)
setData(data);
else
_data = data; // bypass length check
}
/** constructs from base64
@ -84,17 +93,91 @@ public class SigningPublicKey extends SimpleDataStructure {
fromBase64(base64Data);
}
/**
* @return if type unknown, the length of the data, or 128 if no data
*/
public int length() {
return _type.getPubkeyLen();
if (_type != null)
return _type.getPubkeyLen();
if (_data != null)
return _data.length;
return KEYSIZE_BYTES;
}
/**
* @return null if unknown
* @since 0.9.8
*/
public SigType getType() {
return _type;
}
/**
* Up-convert this from an untyped (type 0) SPK to a typed SPK based on the Key Cert given
*
* @throws IllegalArgumentException if this is already typed to a different type
* @since 0.9.12
*/
public SigningPublicKey toTypedKey(KeyCertificate kcert) {
if (_data == null)
throw new IllegalStateException();
SigType newType = kcert.getSigType();
if (_type == newType)
return this;
if (_type != SigType.DSA_SHA1)
throw new IllegalArgumentException("Cannot convert " + _type + " to " + newType);
int newLen = newType.getPubkeyLen();
if (newLen == SigType.DSA_SHA1.getPubkeyLen())
return new SigningPublicKey(newType, _data);
byte[] newData = new byte[newLen];
if (newLen < SigType.DSA_SHA1.getPubkeyLen()) {
// right-justified
System.arraycopy(_data, _data.length - newLen, newData, 0, newLen);
} else {
// full 128 bytes + fragment in kcert
System.arraycopy(_data, 0, newData, 0, _data.length);
System.arraycopy(kcert.getPayload(), KeyCertificate.HEADER_LENGTH, newData, _data.length, newLen - _data.length);
}
return new SigningPublicKey(newType, newData);
}
/**
* Get the portion of this (type 0) SPK that is really padding based on the Key Cert type given,
* if any
*
* @return leading padding length > 0 or null
* @throws IllegalArgumentException if this is already typed to a different type
* @since 0.9.12
*/
public byte[] getPadding(KeyCertificate kcert) {
if (_data == null)
throw new IllegalStateException();
SigType newType = kcert.getSigType();
if (_type == newType)
return null;
if (_type != SigType.DSA_SHA1)
throw new IllegalStateException("Cannot convert " + _type + " to " + newType);
int newLen = newType.getPubkeyLen();
if (newLen >= SigType.DSA_SHA1.getPubkeyLen())
return null;
int padLen = SigType.DSA_SHA1.getPubkeyLen() - newLen;
byte[] pad = new byte[padLen];
System.arraycopy(_data, 0, pad, 0, padLen);
return pad;
}
/**
* Write the data up to a max of 128 bytes.
* If longer, the rest will be written in the KeyCertificate.
* @since 0.9.12
*/
public void writeTruncatedBytes(OutputStream out) throws DataFormatException, IOException {
if (_type.getPubkeyLen() <= KEYSIZE_BYTES)
out.write(_data);
else
out.write(_data, 0, KEYSIZE_BYTES);
}
/**
* @since 0.9.8
*/

View File

@ -71,6 +71,11 @@ public class CreateLeaseSetMessage extends I2CPMessageImpl {
try {
_sessionId = new SessionId();
_sessionId.readBytes(in);
// Revocation is unimplemented.
// As the SPK comes before the LeaseSet, we don't know the key type.
// We could have some sort of callback or state setting so we get the
// expected type from the session. But for now, we just assume it's 20 bytes.
// Clients outside router context should throw in a dummy 20 bytes.
_signingPrivateKey = new SigningPrivateKey();
_signingPrivateKey.readBytes(in);
_privateKey = new PrivateKey();
@ -87,7 +92,7 @@ public class CreateLeaseSetMessage extends I2CPMessageImpl {
if ((_sessionId == null) || (_signingPrivateKey == null) || (_privateKey == null) || (_leaseSet == null))
throw new I2CPMessageException("Unable to write out the message as there is not enough data");
int size = 4 // sessionId
+ SigningPrivateKey.KEYSIZE_BYTES
+ _signingPrivateKey.length()
+ PrivateKey.KEYSIZE_BYTES
+ _leaseSet.size();
ByteArrayOutputStream os = new ByteArrayOutputStream(size);

View File

@ -190,7 +190,7 @@ public class SessionConfig extends DataStructureImpl {
_destination = Destination.create(rawConfig);
_options = DataHelper.readProperties(rawConfig);
_creationDate = DataHelper.readDate(rawConfig);
_signature = new Signature();
_signature = new Signature(_destination.getSigningPublicKey().getType());
_signature.readBytes(rawConfig);
}