use of net.i2p.crypto.SigType in project i2p.i2p by i2p.
the class Packet method verifySignature.
/**
* Determine whether the signature on the data is valid.
*
* @param ctx Application context
* @param from the Destination the data came from
* @param buffer data to validate with signature
* @return true if the signature exists and validates against the data,
* false otherwise.
*/
public boolean verifySignature(I2PAppContext ctx, Destination from, byte[] buffer) {
if (!isFlagSet(FLAG_SIGNATURE_INCLUDED))
return false;
if (_optionSignature == null)
return false;
// prevent receiveNewSyn() ... !active ... sendReset() ... verifySignature ... NPE
if (from == null)
return false;
int size = writtenSize();
if (buffer == null)
buffer = new byte[size];
SigningPublicKey spk = from.getSigningPublicKey();
SigType type = spk.getType();
if (type == null) {
Log l = ctx.logManager().getLog(Packet.class);
if (l.shouldLog(Log.WARN))
l.warn("Unknown sig type in " + from + " cannot verify " + toString());
return false;
}
int written = writePacket(buffer, 0, type.getSigLen());
if (written != size) {
ctx.logManager().getLog(Packet.class).error("Written " + written + " size " + size + " for " + toString(), new Exception("moo"));
return false;
}
// on a close or reset packet where we have a signature without a FROM
if (type != _optionSignature.getType() && type.getSigLen() == _optionSignature.length())
_optionSignature = new Signature(type, _optionSignature.getData());
boolean ok = ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, spk);
if (!ok) {
Log l = ctx.logManager().getLog(Packet.class);
if (l.shouldLog(Log.WARN))
l.warn("Signature failed on " + toString(), new Exception("moo"));
// if (false) {
// l.error(Base64.encode(buffer, 0, size));
// l.error("Signature: " + Base64.encode(_optionSignature.getData()));
// }
}
return ok;
}
use of net.i2p.crypto.SigType in project i2p.i2p by i2p.
the class AddressBean method getSigType.
/**
* Do this the easy way
* @since 0.9.12
*/
public String getSigType() {
// (4 / 3) * (pubkey length + signing key length)
String cert = destination.substring(512);
if (cert.equals("AAAA"))
return _t("DSA 1024 bit");
byte[] enc = Base64.decode(cert);
if (enc == null)
// shouldn't happen
return "invalid";
int type = enc[0] & 0xff;
if (type != Certificate.CERTIFICATE_TYPE_KEY)
return _t("DSA 1024 bit");
int st = ((enc[3] & 0xff) << 8) | (enc[4] & 0xff);
if (st == 0)
return _t("DSA 1024 bit");
SigType stype = SigType.getByCode(st);
if (stype == null)
return _t("Type {0}", st);
return stype.toString();
}
use of net.i2p.crypto.SigType in project i2p.i2p by i2p.
the class RouterInfo method readBytes.
/**
* If verifySig is true,
* this validates the signature while reading in,
* and throws a DataFormatException if the sig is invalid.
* This is faster than reserializing to validate later.
*
* @throws IllegalStateException if RouterInfo was already read in
* @since 0.9
*/
public void readBytes(InputStream in, boolean verifySig) throws DataFormatException, IOException {
if (_signature != null)
throw new IllegalStateException();
_identity = new RouterIdentity();
_identity.readBytes(in);
// can't set the digest until we know the sig type
InputStream din;
MessageDigest digest;
if (verifySig) {
SigType type = _identity.getSigningPublicKey().getType();
if (type != SigType.EdDSA_SHA512_Ed25519) {
// This won't work for EdDSA
digest = _identity.getSigningPublicKey().getType().getDigestInstance();
// TODO any better way?
digest.update(_identity.toByteArray());
din = new DigestInputStream(in, digest);
} else {
digest = null;
din = in;
}
} else {
digest = null;
din = in;
}
// avoid thrashing objects
// Date when = DataHelper.readDate(in);
// if (when == null)
// _published = 0;
// else
// _published = when.getTime();
_published = DataHelper.readLong(din, 8);
int numAddresses = (int) DataHelper.readLong(din, 1);
for (int i = 0; i < numAddresses; i++) {
RouterAddress address = new RouterAddress();
address.readBytes(din);
_addresses.add(address);
}
int numPeers = (int) DataHelper.readLong(din, 1);
if (numPeers == 0) {
_peers = null;
} else {
_peers = new HashSet<Hash>(numPeers);
for (int i = 0; i < numPeers; i++) {
Hash peerIdentityHash = new Hash();
peerIdentityHash.readBytes(din);
_peers.add(peerIdentityHash);
}
}
DataHelper.readProperties(din, _options);
_signature = new Signature(_identity.getSigningPublicKey().getType());
_signature.readBytes(in);
if (verifySig) {
SigType type = _identity.getSigningPublicKey().getType();
if (type != SigType.EdDSA_SHA512_Ed25519) {
// This won't work for EdDSA
SimpleDataStructure hash = _identity.getSigningPublicKey().getType().getHashInstance();
hash.setData(digest.digest());
_isValid = DSAEngine.getInstance().verifySignature(_signature, hash, _identity.getSigningPublicKey());
_validated = true;
} else {
doValidate();
}
if (!_isValid) {
throw new DataFormatException("Bad sig");
}
}
// _log.debug("Read routerInfo: " + toString());
}
use of net.i2p.crypto.SigType in project i2p.i2p by i2p.
the class EstablishState method verifyInbound.
/**
* We are Bob. Verify message #3 from Alice, then send message #4 to Alice.
*
* _aliceIdentSize and _aliceIdent must be set.
* _sz_aliceIdent_tsA_padding_aliceSig must contain at least
* (2 + _aliceIdentSize + 4 + padding + sig) bytes.
*
* Sets _aliceIdent so that we
*
* readAliceRouterIdentity() must have been called previously
*
* Make sure the signatures are correct, and if they are, update the
* NIOConnection with the session key / peer ident / clock skew / iv.
* The NIOConnection itself is responsible for registering with the
* transport
*
* State must be IB_GOT_RI.
* Caller must synch.
*/
private void verifyInbound() {
byte[] b = _sz_aliceIdent_tsA_padding_aliceSig.toByteArray();
try {
int sz = _aliceIdentSize;
// her timestamp from message #3
long tsA = DataHelper.fromLong(b, 2 + sz, 4);
// _tsB is when we sent message #2
// Adjust backward by RTT/2
long now = _context.clock().now();
// rtt from sending #2 to receiving #3
long rtt = now - _con.getCreated();
_peerSkew = (now - (tsA * 1000) - (rtt / 2) + 500) / 1000;
ByteArrayOutputStream baos = new ByteArrayOutputStream(768);
baos.write(_X);
baos.write(_Y);
baos.write(_context.routerHash().getData());
baos.write(DataHelper.toLong(4, tsA));
baos.write(DataHelper.toLong(4, _tsB));
// baos.write(b, 2+sz+4, b.length-2-sz-4-Signature.SIGNATURE_BYTES);
byte[] toVerify = baos.toByteArray();
// if (_log.shouldLog(Log.DEBUG)) {
// _log.debug(prefix()+"checking " + Base64.encode(toVerify, 0, AES_SIZE));
// //_log.debug(prefix()+"check pad " + Base64.encode(b, 2+sz+4, 12));
// }
// handle variable signature size
SigType type = _aliceIdent.getSigningPublicKey().getType();
if (type == null) {
fail("unsupported sig type");
return;
}
byte[] s = new byte[type.getSigLen()];
System.arraycopy(b, b.length - s.length, s, 0, s.length);
Signature sig = new Signature(type, s);
boolean ok = _context.dsa().verifySignature(sig, toVerify, _aliceIdent.getSigningPublicKey());
if (ok) {
// get inet-addr
InetAddress addr = this._con.getChannel().socket().getInetAddress();
byte[] ip = (addr == null) ? null : addr.getAddress();
if (_context.banlist().isBanlistedForever(_aliceIdent.calculateHash())) {
if (_log.shouldLog(Log.WARN))
_log.warn("Dropping inbound connection from permanently banlisted peer: " + _aliceIdent.calculateHash());
// rather than doing the whole handshake
if (ip != null)
_context.blocklist().add(ip);
fail("Peer is banlisted forever: " + _aliceIdent.calculateHash());
return;
}
if (ip != null)
_transport.setIP(_aliceIdent.calculateHash(), ip);
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "verification successful for " + _con);
long diff = 1000 * Math.abs(_peerSkew);
if (!_context.clock().getUpdatedSuccessfully()) {
// Adjust the clock one time in desperation
// This isn't very likely, outbound will do it first
// We are Bob, she is Alice, adjust to match Alice
_context.clock().setOffset(1000 * (0 - _peerSkew), true);
_peerSkew = 0;
if (diff != 0)
_log.logAlways(Log.WARN, "NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff));
} else if (diff >= Router.CLOCK_FUDGE_FACTOR) {
_context.statManager().addRateData("ntcp.invalidInboundSkew", diff);
_transport.markReachable(_aliceIdent.calculateHash(), true);
// Only banlist if we know what time it is
_context.banlist().banlistRouter(DataHelper.formatDuration(diff), _aliceIdent.calculateHash(), _x("Excessive clock skew: {0}"));
_transport.setLastBadSkew(_peerSkew);
fail("Clocks too skewed (" + diff + " ms)", null, true);
return;
} else if (_log.shouldLog(Log.DEBUG)) {
_log.debug(prefix() + "Clock skew: " + diff + " ms");
}
_con.setRemotePeer(_aliceIdent);
sendInboundConfirm(_aliceIdent, tsA);
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "e_bobSig is " + _e_bobSig.length + " bytes long");
// reuse buf
byte[] iv = _curEncrypted;
System.arraycopy(_e_bobSig, _e_bobSig.length - AES_SIZE, iv, 0, AES_SIZE);
// this does not copy the IV, do not release to cache
// We are Bob, she is Alice, clock skew is Alice-Bob
// skew in seconds
_con.finishInboundEstablishment(_dh.getSessionKey(), _peerSkew, iv, _prevEncrypted);
releaseBufs(true);
if (_log.shouldLog(Log.INFO))
_log.info(prefix() + "Verified remote peer as " + _aliceIdent.calculateHash());
changeState(State.VERIFIED);
} else {
_context.statManager().addRateData("ntcp.invalidInboundSignature", 1);
fail("Peer verification failed - spoof of " + _aliceIdent.calculateHash() + "?");
}
} catch (IOException ioe) {
_context.statManager().addRateData("ntcp.invalidInboundIOE", 1);
fail("Error verifying peer", ioe);
}
}
use of net.i2p.crypto.SigType in project i2p.i2p by i2p.
the class SAMv1Handler method execDestMessage.
/* Parse and execute a DEST message*/
protected boolean execDestMessage(String opcode, Properties props) {
if (opcode.equals("GENERATE")) {
String sigTypeStr = props.getProperty("SIGNATURE_TYPE");
SigType sigType;
if (sigTypeStr != null) {
sigType = SigType.parseSigType(sigTypeStr);
if (sigType == null) {
writeString("DEST REPLY RESULT=I2P_ERROR MESSAGE=\"SIGNATURE_TYPE " + sigTypeStr + " unsupported\"\n");
return false;
}
} else {
sigType = SigType.DSA_SHA1;
}
ByteArrayOutputStream priv = new ByteArrayOutputStream(663);
ByteArrayOutputStream pub = new ByteArrayOutputStream(387);
SAMUtils.genRandomKey(priv, pub, sigType);
return writeString("DEST REPLY" + " PUB=" + Base64.encode(pub.toByteArray()) + " PRIV=" + Base64.encode(priv.toByteArray()) + "\n");
} else {
writeString("DEST REPLY RESULT=I2P_ERROR MESSAGE=\"DEST GENERATE required\"");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Unrecognized DEST message opcode: \"" + opcode + "\"");
return false;
}
}
Aggregations