use of net.i2p.data.Signature in project i2p.i2p by i2p.
the class KeyGenerator method testSig.
private static void testSig(SigType type, int runs) throws GeneralSecurityException {
byte[] src = new byte[512];
double gtime = 0;
long stime = 0;
long vtime = 0;
SimpleDataStructure[] keys = null;
long st = System.nanoTime();
// RSA super slow, limit to 5
int genruns = (type.getBaseAlgorithm() == SigAlgo.RSA) ? Math.min(runs, 5) : runs;
for (int i = 0; i < genruns; i++) {
keys = KeyGenerator.getInstance().generateSigningKeys(type);
}
long en = System.nanoTime();
gtime = ((en - st) / (1000 * 1000d)) / genruns;
System.out.println(type + " key gen " + genruns + " times: " + gtime + " ms each");
SigningPublicKey pubkey = (SigningPublicKey) keys[0];
SigningPrivateKey privkey = (SigningPrivateKey) keys[1];
SigningPublicKey pubkey2 = getSigningPublicKey(privkey);
if (pubkey.equals(pubkey2))
System.out.println(type + " private-to-public test PASSED");
else
System.out.println(type + " private-to-public test FAILED");
// System.out.println("privkey " + keys[1]);
MessageDigest md = type.getDigestInstance();
for (int i = 0; i < runs; i++) {
RandomSource.getInstance().nextBytes(src);
md.update(src);
byte[] sha = md.digest();
SimpleDataStructure hash = type.getHashInstance();
hash.setData(sha);
long start = System.nanoTime();
Signature sig = DSAEngine.getInstance().sign(src, privkey);
Signature sig2 = DSAEngine.getInstance().sign(hash, privkey);
if (sig == null)
throw new GeneralSecurityException("signature generation failed");
if (sig2 == null)
throw new GeneralSecurityException("signature generation (H) failed");
long mid = System.nanoTime();
boolean ok = DSAEngine.getInstance().verifySignature(sig, src, pubkey);
boolean ok2 = DSAEngine.getInstance().verifySignature(sig2, hash, pubkey);
long end = System.nanoTime();
stime += mid - start;
vtime += end - mid;
if (!ok)
throw new GeneralSecurityException(type + " V(S(data)) fail");
if (!ok2)
throw new GeneralSecurityException(type + " V(S(H(data))) fail");
}
stime /= 1000 * 1000;
vtime /= 1000 * 1000;
System.out.println(type + " sign/verify " + runs + " times: " + (vtime + stime) + " ms = " + (((double) stime) / runs) + " each sign, " + (((double) vtime) / runs) + " each verify, " + (((double) (stime + vtime)) / runs) + " s+v");
}
use of net.i2p.data.Signature in project i2p.i2p by i2p.
the class DSATest method testMultiple.
public void testMultiple() {
for (int i = 0; i < 25; i++) {
byte[] message = new byte[256];
_context.random().nextBytes(message);
Object[] keys = KeyGenerator.getInstance().generateSigningKeypair();
SigningPublicKey pubkey = (SigningPublicKey) keys[0];
SigningPrivateKey privkey = (SigningPrivateKey) keys[1];
Signature s = DSAEngine.getInstance().sign(message, privkey);
Signature s1 = DSAEngine.getInstance().sign(new ByteArrayInputStream(message), privkey);
assertTrue(DSAEngine.getInstance().verifySignature(s, message, pubkey));
assertTrue(DSAEngine.getInstance().verifySignature(s1, new ByteArrayInputStream(message), pubkey));
assertTrue(DSAEngine.getInstance().verifySignature(s1, message, pubkey));
assertTrue(DSAEngine.getInstance().verifySignature(s, new ByteArrayInputStream(message), pubkey));
}
}
use of net.i2p.data.Signature in project i2p.i2p by i2p.
the class EstablishState method sendInboundConfirm.
/**
* We are Bob. Send message #4 to Alice.
*
* State must be VERIFIED.
* Caller must synch.
*/
private void sendInboundConfirm(RouterIdentity alice, long tsA) {
// send Alice E(S(X+Y+Alice.identHash+tsA+tsB), sk, prev)
byte[] toSign = new byte[XY_SIZE + XY_SIZE + 32 + 4 + 4];
int off = 0;
System.arraycopy(_X, 0, toSign, off, XY_SIZE);
off += XY_SIZE;
System.arraycopy(_Y, 0, toSign, off, XY_SIZE);
off += XY_SIZE;
Hash h = alice.calculateHash();
System.arraycopy(h.getData(), 0, toSign, off, 32);
off += 32;
DataHelper.toLong(toSign, off, 4, tsA);
off += 4;
DataHelper.toLong(toSign, off, 4, _tsB);
off += 4;
// handle variable signature size
Signature sig = _context.dsa().sign(toSign, _context.keyManager().getSigningPrivateKey());
int siglen = sig.length();
int rem = siglen % AES_SIZE;
int padding;
if (rem > 0)
padding = AES_SIZE - rem;
else
padding = 0;
byte[] preSig = new byte[siglen + padding];
System.arraycopy(sig.getData(), 0, preSig, 0, siglen);
if (padding > 0)
_context.random().nextBytes(preSig, siglen, padding);
_e_bobSig = new byte[preSig.length];
_context.aes().encrypt(preSig, 0, _e_bobSig, 0, _dh.getSessionKey(), _e_hXY_tsB, HXY_TSB_PAD_SIZE - AES_SIZE, _e_bobSig.length);
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "Sending encrypted inbound confirmation");
_transport.getPumper().wantsWrite(_con, _e_bobSig);
}
use of net.i2p.data.Signature in project i2p.i2p by i2p.
the class EstablishState method receiveOutbound.
/**
* We are Alice, so receive these bytes as part of an outbound connection.
* This method receives messages 2 and 4, and sends message 3.
*
* All data must be copied out of the buffer as Reader.processRead()
* will return it to the pool.
*
* Caller must synch.
*
* FIXME none of the _state comparisons use _stateLock, but whole thing
* is synchronized, should be OK. See isComplete()
*/
private void receiveOutbound(ByteBuffer src) {
// Read in Y, which is the first part of message #2
while (_state == State.OB_SENT_X && src.hasRemaining()) {
byte c = src.get();
_Y[_received++] = c;
// if (_log.shouldLog(Log.DEBUG)) _log.debug("recv x" + (int)c + " received=" + _received);
if (_received >= XY_SIZE) {
try {
_dh.setPeerPublicValue(_Y);
// force the calc
_dh.getSessionKey();
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "DH session key calculated (" + _dh.getSessionKey().toBase64() + ")");
changeState(State.OB_GOT_Y);
} catch (DHSessionKeyBuilder.InvalidPublicParameterException e) {
_context.statManager().addRateData("ntcp.invalidDH", 1);
fail("Invalid X", e);
return;
}
}
}
// Read in the rest of message #2
while (_state == State.OB_GOT_Y && src.hasRemaining()) {
int i = _received - XY_SIZE;
_received++;
byte c = src.get();
_e_hXY_tsB[i] = c;
// _log.debug(prefix() + "recv _e_hXY_tsB " + (int)c + " received=" + _received);
if (i + 1 >= HXY_TSB_PAD_SIZE) {
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "received _e_hXY_tsB fully");
byte[] hXY_tsB = new byte[HXY_TSB_PAD_SIZE];
_context.aes().decrypt(_e_hXY_tsB, 0, hXY_tsB, 0, _dh.getSessionKey(), _Y, XY_SIZE - AES_SIZE, HXY_TSB_PAD_SIZE);
byte[] XY = new byte[XY_SIZE + XY_SIZE];
System.arraycopy(_X, 0, XY, 0, XY_SIZE);
System.arraycopy(_Y, 0, XY, XY_SIZE, XY_SIZE);
byte[] h = SimpleByteCache.acquire(HXY_SIZE);
_context.sha().calculateHash(XY, 0, XY_SIZE + XY_SIZE, h, 0);
// _log.debug(prefix() + "h(XY)=" + h.toBase64());
if (!DataHelper.eq(h, 0, hXY_tsB, 0, HXY_SIZE)) {
SimpleByteCache.release(h);
_context.statManager().addRateData("ntcp.invalidHXY", 1);
fail("Invalid H(X+Y) - mitm attack attempted?");
return;
}
SimpleByteCache.release(h);
changeState(State.OB_GOT_HXY);
// their (Bob's) timestamp in seconds
_tsB = DataHelper.fromLong(hXY_tsB, HXY_SIZE, 4);
long now = _context.clock().now();
// rtt from sending #1 to receiving #2
long rtt = now - _con.getCreated();
// our (Alice's) timestamp in seconds
_tsA = (now + 500) / 1000;
_peerSkew = (now - (_tsB * 1000) - (rtt / 2) + 500) / 1000;
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "h(X+Y) is correct, skew = " + _peerSkew);
// the skew is not authenticated yet, but it is certainly fatal to
// the establishment, so fail hard if appropriate
long diff = 1000 * Math.abs(_peerSkew);
if (!_context.clock().getUpdatedSuccessfully()) {
// Adjust the clock one time in desperation
// We are Alice, he is Bob, adjust to match Bob
_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.invalidOutboundSkew", diff);
_transport.markReachable(_con.getRemotePeer().calculateHash(), false);
// Only banlist if we know what time it is
_context.banlist().banlistRouter(DataHelper.formatDuration(diff), _con.getRemotePeer().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");
}
// now prepare and send our response
// send E(#+Alice.identity+tsA+padding+S(X+Y+Bob.identHash+tsA+tsB), sk, hX_xor_Bob.identHash[16:31])
// +12;
int sigSize = XY_SIZE + XY_SIZE + HXY_SIZE + 4 + 4;
byte[] preSign = new byte[sigSize];
System.arraycopy(_X, 0, preSign, 0, XY_SIZE);
System.arraycopy(_Y, 0, preSign, XY_SIZE, XY_SIZE);
System.arraycopy(_con.getRemotePeer().calculateHash().getData(), 0, preSign, XY_SIZE + XY_SIZE, HXY_SIZE);
DataHelper.toLong(preSign, XY_SIZE + XY_SIZE + HXY_SIZE, 4, _tsA);
DataHelper.toLong(preSign, XY_SIZE + XY_SIZE + HXY_SIZE + 4, 4, _tsB);
// hXY_tsB has 12 bytes of padding (size=48, tsB=4 + hXY=32)
// System.arraycopy(hXY_tsB, hXY_tsB.length-12, preSign, _X.length+_Y.length+Hash.HASH_LENGTH+4+4, 12);
// byte sigPad[] = new byte[padSig];
// _context.random().nextBytes(sigPad);
// System.arraycopy(sigPad, 0, preSign, _X.length+_Y.length+Hash.HASH_LENGTH+4+4, padSig);
Signature sig = _context.dsa().sign(preSign, _context.keyManager().getSigningPrivateKey());
// if (_log.shouldLog(Log.DEBUG)) {
// _log.debug(prefix()+"signing " + Base64.encode(preSign));
// }
byte[] ident = _context.router().getRouterInfo().getIdentity().toByteArray();
// handle variable signature size
int min = 2 + ident.length + 4 + sig.length();
int rem = min % AES_SIZE;
int padding = 0;
if (rem > 0)
padding = AES_SIZE - rem;
byte[] preEncrypt = new byte[min + padding];
DataHelper.toLong(preEncrypt, 0, 2, ident.length);
System.arraycopy(ident, 0, preEncrypt, 2, ident.length);
DataHelper.toLong(preEncrypt, 2 + ident.length, 4, _tsA);
if (padding > 0)
_context.random().nextBytes(preEncrypt, 2 + ident.length + 4, padding);
System.arraycopy(sig.getData(), 0, preEncrypt, 2 + ident.length + 4 + padding, sig.length());
_prevEncrypted = new byte[preEncrypt.length];
_context.aes().encrypt(preEncrypt, 0, _prevEncrypted, 0, _dh.getSessionKey(), _hX_xor_bobIdentHash, _hX_xor_bobIdentHash.length - AES_SIZE, preEncrypt.length);
// if (_log.shouldLog(Log.DEBUG)) {
// _log.debug(prefix() + "unencrypted response to Bob: " + Base64.encode(preEncrypt));
// _log.debug(prefix() + "encrypted response to Bob: " + Base64.encode(_prevEncrypted));
// }
// send 'er off (when the bw limiter says, etc)
changeState(State.OB_SENT_RI);
_transport.getPumper().wantsWrite(_con, _prevEncrypted);
}
}
// Read in message #4
if (_state == State.OB_SENT_RI && src.hasRemaining()) {
// we are receiving their confirmation
// recv E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev)
int off = 0;
if (_e_bobSig == null) {
// handle variable signature size
int siglen = _con.getRemotePeer().getSigningPublicKey().getType().getSigLen();
int rem = siglen % AES_SIZE;
int padding;
if (rem > 0)
padding = AES_SIZE - rem;
else
padding = 0;
_e_bobSig = new byte[siglen + padding];
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "receiving E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " + src.hasRemaining() + ")");
} else {
off = _received - XY_SIZE - HXY_TSB_PAD_SIZE;
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "continuing to receive E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " + src.hasRemaining() + " off=" + off + " recv=" + _received + ")");
}
while (_state == State.OB_SENT_RI && src.hasRemaining()) {
// if (_log.shouldLog(Log.DEBUG)) _log.debug(prefix()+"recv bobSig received=" + _received);
_e_bobSig[off++] = src.get();
_received++;
if (off >= _e_bobSig.length) {
changeState(State.OB_GOT_SIG);
// if (_log.shouldLog(Log.DEBUG))
// _log.debug(prefix() + "received E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev): " + Base64.encode(_e_bobSig));
byte[] bobSig = new byte[_e_bobSig.length];
_context.aes().decrypt(_e_bobSig, 0, bobSig, 0, _dh.getSessionKey(), _e_hXY_tsB, HXY_TSB_PAD_SIZE - AES_SIZE, _e_bobSig.length);
// ignore the padding
// handle variable signature size
SigType type = _con.getRemotePeer().getSigningPublicKey().getType();
int siglen = type.getSigLen();
byte[] bobSigData = new byte[siglen];
System.arraycopy(bobSig, 0, bobSigData, 0, siglen);
Signature sig = new Signature(type, bobSigData);
byte[] toVerify = new byte[XY_SIZE + XY_SIZE + HXY_SIZE + 4 + 4];
int voff = 0;
System.arraycopy(_X, 0, toVerify, voff, XY_SIZE);
voff += XY_SIZE;
System.arraycopy(_Y, 0, toVerify, voff, XY_SIZE);
voff += XY_SIZE;
System.arraycopy(_context.routerHash().getData(), 0, toVerify, voff, HXY_SIZE);
voff += HXY_SIZE;
DataHelper.toLong(toVerify, voff, 4, _tsA);
voff += 4;
DataHelper.toLong(toVerify, voff, 4, _tsB);
voff += 4;
boolean ok = _context.dsa().verifySignature(sig, toVerify, _con.getRemotePeer().getSigningPublicKey());
if (!ok) {
_context.statManager().addRateData("ntcp.invalidSignature", 1);
fail("Signature was invalid - attempt to spoof " + _con.getRemotePeer().calculateHash().toBase64() + "?");
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "signature verified from Bob. done!");
prepareExtra(src);
// reuse buf
byte[] nextWriteIV = _curEncrypted;
System.arraycopy(_prevEncrypted, _prevEncrypted.length - AES_SIZE, nextWriteIV, 0, AES_SIZE);
// this does not copy the nextWriteIV, do not release to cache
// We are Alice, he is Bob, clock skew is Bob - Alice
// skew in seconds
_con.finishOutboundEstablishment(_dh.getSessionKey(), _peerSkew, nextWriteIV, _e_bobSig);
releaseBufs(true);
// if socket gets closed this will be null - prevent NPE
InetAddress ia = _con.getChannel().socket().getInetAddress();
if (ia != null)
_transport.setIP(_con.getRemotePeer().calculateHash(), ia.getAddress());
changeState(State.VERIFIED);
}
return;
}
}
}
}
use of net.i2p.data.Signature in project i2p.i2p by i2p.
the class OutboundEstablishState method decryptSignature.
/**
* decrypt the signature (and subsequent pad bytes) with the
* additional layer of encryption using the negotiated key along side
* the packet's IV
*
* Caller must synch on this.
* Only call this once! Decrypts in-place.
*/
private void decryptSignature() {
if (_receivedEncryptedSignature == null)
throw new NullPointerException("encrypted signature is null! this=" + this.toString());
if (_sessionKey == null)
throw new NullPointerException("SessionKey is null!");
if (_receivedIV == null)
throw new NullPointerException("IV is null!");
_context.aes().decrypt(_receivedEncryptedSignature, 0, _receivedEncryptedSignature, 0, _sessionKey, _receivedIV, _receivedEncryptedSignature.length);
// handle variable signature size
SigType type = _remotePeer.getSigningPublicKey().getType();
// if type == null throws NPE
int sigLen = type.getSigLen();
int mod = sigLen % 16;
if (mod != 0) {
byte[] signatureBytes = new byte[sigLen];
System.arraycopy(_receivedEncryptedSignature, 0, signatureBytes, 0, sigLen);
_receivedSignature = new Signature(type, signatureBytes);
} else {
_receivedSignature = new Signature(type, _receivedEncryptedSignature);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Decrypted received signature: " + Base64.encode(_receivedSignature.getData()));
}
Aggregations