use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class CreateRouterInfoJob method createRouterInfo.
/**
* Writes 6 files: router.info (standard RI format),
* router.keys.dat, and 4 individual key files under keyBackup/
*
* router.keys.dat file format: This is the
* same "eepPriv.dat" format used by the client code,
* as documented in PrivateKeyFile.
*
* Old router.keys file format: Note that this is NOT the
* same "eepPriv.dat" format used by the client code.
*<pre>
* - Private key (256 bytes)
* - Signing Private key (20 bytes)
* - Public key (256 bytes)
* - Signing Public key (128 bytes)
* Total 660 bytes
*</pre>
*
* Caller must hold Router.routerInfoFileLock.
*/
RouterInfo createRouterInfo() {
SigType type = getSigTypeConfig(getContext());
RouterInfo info = new RouterInfo();
OutputStream fos1 = null;
try {
info.setAddresses(getContext().commSystem().createAddresses());
// not necessary, in constructor
// info.setPeers(new HashSet());
info.setPublished(getCurrentPublishDate(getContext()));
Object[] keypair = getContext().keyGenerator().generatePKIKeypair();
PublicKey pubkey = (PublicKey) keypair[0];
PrivateKey privkey = (PrivateKey) keypair[1];
SimpleDataStructure[] signingKeypair = getContext().keyGenerator().generateSigningKeys(type);
SigningPublicKey signingPubKey = (SigningPublicKey) signingKeypair[0];
SigningPrivateKey signingPrivKey = (SigningPrivateKey) signingKeypair[1];
RouterIdentity ident = new RouterIdentity();
Certificate cert = createCertificate(getContext(), signingPubKey);
ident.setCertificate(cert);
ident.setPublicKey(pubkey);
ident.setSigningPublicKey(signingPubKey);
byte[] padding;
int padLen = SigningPublicKey.KEYSIZE_BYTES - signingPubKey.length();
if (padLen > 0) {
padding = new byte[padLen];
getContext().random().nextBytes(padding);
ident.setPadding(padding);
} else {
padding = null;
}
info.setIdentity(ident);
Properties stats = getContext().statPublisher().publishStatistics(ident.getHash());
info.setOptions(stats);
info.sign(signingPrivKey);
if (!info.isValid())
throw new DataFormatException("RouterInfo we just built is invalid: " + info);
// remove router.keys
(new File(getContext().getRouterDir(), KEYS_FILENAME)).delete();
// write router.info
File ifile = new File(getContext().getRouterDir(), INFO_FILENAME);
fos1 = new BufferedOutputStream(new SecureFileOutputStream(ifile));
info.writeBytes(fos1);
// write router.keys.dat
File kfile = new File(getContext().getRouterDir(), KEYS2_FILENAME);
PrivateKeyFile pkf = new PrivateKeyFile(kfile, pubkey, signingPubKey, cert, privkey, signingPrivKey, padding);
pkf.write();
// set or overwrite old random keys
Map<String, String> map = new HashMap<String, String>(2);
byte[] rk = new byte[32];
getContext().random().nextBytes(rk);
map.put(Router.PROP_IB_RANDOM_KEY, Base64.encode(rk));
getContext().random().nextBytes(rk);
map.put(Router.PROP_OB_RANDOM_KEY, Base64.encode(rk));
getContext().router().saveConfig(map, null);
getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
if (_log.shouldLog(Log.INFO))
_log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]");
getContext().router().eventLog().addEvent(EventLog.REKEYED, ident.calculateHash().toBase64());
} catch (GeneralSecurityException gse) {
_log.log(Log.CRIT, "Error building the new router information", gse);
} catch (DataFormatException dfe) {
_log.log(Log.CRIT, "Error building the new router information", dfe);
} catch (IOException ioe) {
_log.log(Log.CRIT, "Error writing out the new router information", ioe);
} finally {
if (fos1 != null)
try {
fos1.close();
} catch (IOException ioe) {
}
}
return info;
}
use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class LoadRouterInfoJob method loadRouterInfo.
/**
* Loads router.info and either router.keys.dat or router.keys.
*
* See CreateRouterInfoJob for file formats
*/
private void loadRouterInfo() {
RouterInfo info = null;
File rif = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
boolean infoExists = rif.exists();
File rkf = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS_FILENAME);
boolean keysExist = rkf.exists();
File rkf2 = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
boolean keys2Exist = rkf2.exists();
InputStream fis1 = null;
try {
// so pretend the RI isn't there if there is no keyfile
if (infoExists && (keys2Exist || keysExist)) {
fis1 = new BufferedInputStream(new FileInputStream(rif));
info = new RouterInfo();
info.readBytes(fis1);
// Catch this here before it all gets worse
if (!info.isValid())
throw new DataFormatException("Our RouterInfo has a bad signature");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Reading in routerInfo from " + rif.getAbsolutePath() + " and it has " + info.getAddresses().size() + " addresses");
// don't reuse if family name changed
if (DataHelper.eq(info.getOption(FamilyKeyCrypto.OPT_NAME), getContext().getProperty(FamilyKeyCrypto.PROP_FAMILY_NAME))) {
_us = info;
} else {
_log.logAlways(Log.WARN, "NetDb family name changed");
}
}
if (keys2Exist || keysExist) {
KeyData kd = readKeyData(rkf, rkf2);
PublicKey pubkey = kd.routerIdentity.getPublicKey();
SigningPublicKey signingPubKey = kd.routerIdentity.getSigningPublicKey();
PrivateKey privkey = kd.privateKey;
SigningPrivateKey signingPrivKey = kd.signingPrivateKey;
SigType stype = signingPubKey.getType();
// check if the sigtype config changed
SigType cstype = CreateRouterInfoJob.getSigTypeConfig(getContext());
boolean sigTypeChanged = stype != cstype;
if (sigTypeChanged && getContext().getProperty(CreateRouterInfoJob.PROP_ROUTER_SIGTYPE) == null) {
// TODO reduce to ~3 (i.e. increase probability) in future release
if (getContext().random().nextInt(4) > 0) {
sigTypeChanged = false;
if (_log.shouldWarn())
_log.warn("Deferring RI rekey from " + stype + " to " + cstype);
}
}
if (sigTypeChanged || shouldRebuild(privkey)) {
if (_us != null) {
Hash h = _us.getIdentity().getHash();
_log.logAlways(Log.WARN, "Deleting old router identity " + h.toBase64());
// the netdb hasn't started yet, but we want to delete the RI
File f = PersistentDataStore.getRouterInfoFile(getContext(), h);
f.delete();
// the banlist can be called at any time
getContext().banlist().banlistRouterForever(h, "Our previous identity");
_us = null;
}
if (sigTypeChanged)
_log.logAlways(Log.WARN, "Rebuilding RouterInfo with new signature type " + cstype);
// windows... close before deleting
if (fis1 != null) {
try {
fis1.close();
} catch (IOException ioe) {
}
fis1 = null;
}
rif.delete();
rkf.delete();
rkf2.delete();
return;
}
getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
}
} catch (IOException ioe) {
_log.log(Log.CRIT, "Error reading the router info from " + rif.getAbsolutePath() + " and the keys from " + rkf.getAbsolutePath(), ioe);
_us = null;
// windows... close before deleting
if (fis1 != null) {
try {
fis1.close();
} catch (IOException ioe2) {
}
fis1 = null;
}
rif.delete();
rkf.delete();
rkf2.delete();
} catch (DataFormatException dfe) {
_log.log(Log.CRIT, "Corrupt router info or keys at " + rif.getAbsolutePath() + " / " + rkf.getAbsolutePath(), dfe);
_us = null;
// windows... close before deleting
if (fis1 != null) {
try {
fis1.close();
} catch (IOException ioe) {
}
fis1 = null;
}
rif.delete();
rkf.delete();
rkf2.delete();
} finally {
if (fis1 != null)
try {
fis1.close();
} catch (IOException ioe) {
}
}
}
use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class TunnelPeerSelector method selectExplicit.
/**
* For debugging, also possibly for restricted routes?
* Needs analysis and testing
* @return should always be false
*/
protected List<Hash> selectExplicit(TunnelPoolSettings settings, int length) {
String peers = null;
Properties opts = settings.getUnknownOptions();
if (opts != null)
peers = opts.getProperty("explicitPeers");
if (peers == null)
peers = ctx.getProperty("explicitPeers");
List<Hash> rv = new ArrayList<Hash>();
StringTokenizer tok = new StringTokenizer(peers, ",");
while (tok.hasMoreTokens()) {
String peerStr = tok.nextToken();
Hash peer = new Hash();
try {
peer.fromBase64(peerStr);
if (ctx.profileOrganizer().isSelectable(peer)) {
rv.add(peer);
} else {
if (log.shouldLog(Log.DEBUG))
log.debug("Explicit peer is not selectable: " + peerStr);
}
} catch (DataFormatException dfe) {
if (log.shouldLog(Log.ERROR))
log.error("Explicit peer is improperly formatted (" + peerStr + ")", dfe);
}
}
int sz = rv.size();
Collections.shuffle(rv, ctx.random());
while (rv.size() > length) rv.remove(0);
if (log.shouldLog(Log.INFO)) {
StringBuilder buf = new StringBuilder();
if (settings.getDestinationNickname() != null)
buf.append("peers for ").append(settings.getDestinationNickname());
else if (settings.getDestination() != null)
buf.append("peers for ").append(settings.getDestination().toBase64());
else
buf.append("peers for exploratory ");
if (settings.isInbound())
buf.append(" inbound");
else
buf.append(" outbound");
buf.append(" peers: ").append(rv);
buf.append(", out of ").append(sz).append(" (not including self)");
log.info(buf.toString());
}
if (settings.isInbound())
rv.add(0, ctx.routerHash());
else
rv.add(ctx.routerHash());
return rv;
}
use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class BuildMessageProcessor method decrypt.
/**
* Decrypt the record targetting us, encrypting all of the other records with the included
* reply key and IV. The original, encrypted record targetting us is removed from the request
* message (so that the reply can be placed in that position after going through the decrypted
* request record).
*
* Note that this layer-decrypts the build records in-place.
* Do not call this more than once for a given message.
*
* @return the current hop's decrypted record or null on failure
*/
public BuildRequestRecord decrypt(TunnelBuildMessage msg, Hash ourHash, PrivateKey privKey) {
BuildRequestRecord rv = null;
int ourHop = -1;
long beforeActualDecrypt = 0;
long afterActualDecrypt = 0;
byte[] ourHashData = ourHash.getData();
long beforeLoop = System.currentTimeMillis();
for (int i = 0; i < msg.getRecordCount(); i++) {
EncryptedBuildRecord rec = msg.getRecord(i);
int len = BuildRequestRecord.PEER_SIZE;
boolean eq = DataHelper.eq(ourHashData, 0, rec.getData(), 0, len);
if (eq) {
beforeActualDecrypt = System.currentTimeMillis();
try {
rv = new BuildRequestRecord(ctx, privKey, rec);
afterActualDecrypt = System.currentTimeMillis();
// i2pd bug
boolean isBad = SessionKey.INVALID_KEY.equals(rv.readReplyKey());
if (isBad) {
if (log.shouldLog(Log.WARN))
log.warn(msg.getUniqueId() + ": Bad reply key: " + rv);
ctx.statManager().addRateData("tunnel.buildRequestBadReplyKey", 1);
return null;
}
// The spec says to feed the 32-byte AES-256 reply key into the Bloom filter.
// But we were using the first 32 bytes of the encrypted reply.
// Fixed in 0.9.24
boolean isDup = _filter.add(rv.getData(), BuildRequestRecord.OFF_REPLY_KEY, 32);
if (isDup) {
if (log.shouldLog(Log.WARN))
log.warn(msg.getUniqueId() + ": Dup record: " + rv);
ctx.statManager().addRateData("tunnel.buildRequestDup", 1);
return null;
}
if (log.shouldLog(Log.DEBUG))
log.debug(msg.getUniqueId() + ": Matching record: " + rv);
ourHop = i;
// TODO should we keep looking for a second match and fail if found?
break;
} catch (DataFormatException dfe) {
if (log.shouldLog(Log.WARN))
log.warn(msg.getUniqueId() + ": Matching record decrypt failure", dfe);
// out there with the same first 16 bytes, go around again
continue;
}
}
}
if (rv == null) {
// none of the records matched, b0rk
if (log.shouldLog(Log.WARN))
log.warn(msg.getUniqueId() + ": No matching record");
return null;
}
long beforeEncrypt = System.currentTimeMillis();
SessionKey replyKey = rv.readReplyKey();
byte[] iv = rv.readReplyIV();
for (int i = 0; i < msg.getRecordCount(); i++) {
if (i != ourHop) {
EncryptedBuildRecord data = msg.getRecord(i);
// if (log.shouldLog(Log.DEBUG))
// log.debug("Encrypting record " + i + "/? with replyKey " + replyKey.toBase64() + "/" + Base64.encode(iv));
// encrypt in-place, corrupts SDS
byte[] bytes = data.getData();
ctx.aes().encrypt(bytes, 0, bytes, 0, replyKey, iv, 0, EncryptedBuildRecord.LENGTH);
}
}
long afterEncrypt = System.currentTimeMillis();
msg.setRecord(ourHop, null);
if (afterEncrypt - beforeLoop > 1000) {
if (log.shouldLog(Log.WARN))
log.warn("Slow decryption, total=" + (afterEncrypt - beforeLoop) + " looping=" + (beforeEncrypt - beforeLoop) + " decrypt=" + (afterActualDecrypt - beforeActualDecrypt) + " encrypt=" + (afterEncrypt - beforeEncrypt));
}
return rv;
}
use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class SSUDemo method storeMyInfo.
private static void storeMyInfo(RouterInfo info) {
File infoDir = getInfoDir();
if (!infoDir.exists())
infoDir.mkdirs();
FileOutputStream fos = null;
File infoFile = new File(infoDir, info.getIdentity().calculateHash().toBase64());
infoFile.deleteOnExit();
try {
fos = new FileOutputStream(infoFile);
info.writeBytes(fos);
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (DataFormatException dfe) {
dfe.printStackTrace();
} finally {
if (fos != null)
try {
fos.close();
} catch (IOException ioe) {
}
}
System.out.println("Our info stored at: " + infoFile.getAbsolutePath());
}
Aggregations