forked from I2P_Developers/i2p.i2p
Ratchet: WIP on NSR send/recv
This commit is contained in:
@ -150,10 +150,9 @@ public final class ECIESAEADEngine {
|
||||
_log.debug("Decrypting existing session encrypted with tag: " + st.toString() + ": key: " + key.toBase64() + ": " + data.length + " bytes " /* + Base64.encode(data, 0, 64) */ );
|
||||
|
||||
HandshakeState state = key.getHandshakeState();
|
||||
if (state != null) {
|
||||
if (state == null) {
|
||||
decrypted = decryptExistingSession(tag, data, key, targetPrivateKey);
|
||||
} else if (data.length >= MIN_NSR_SIZE) {
|
||||
/** TODO find the state
|
||||
try {
|
||||
state = state.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
@ -161,9 +160,7 @@ public final class ECIESAEADEngine {
|
||||
_log.warn("ECIES decrypt fail: clone()", e);
|
||||
return null;
|
||||
}
|
||||
decrypted = decryptNewSessionReply(tag, data, state);
|
||||
**/
|
||||
decrypted = null;
|
||||
decrypted = decryptNewSessionReply(tag, data, state, keyManager);
|
||||
} else {
|
||||
decrypted = null;
|
||||
if (_log.shouldWarn())
|
||||
@ -180,7 +177,7 @@ public final class ECIESAEADEngine {
|
||||
}
|
||||
} else if (data.length >= MIN_NS_SIZE) {
|
||||
if (shouldDebug) _log.debug("IB Tag " + st + " not found, trying NS decrypt");
|
||||
decrypted = decryptNewSession(data, targetPrivateKey);
|
||||
decrypted = decryptNewSession(data, targetPrivateKey, keyManager);
|
||||
if (decrypted != null) {
|
||||
if (shouldDebug) _log.debug("NS decrypt success");
|
||||
_context.statManager().updateFrequency("crypto.eciesAEAD.decryptNewSession");
|
||||
@ -216,7 +213,7 @@ public final class ECIESAEADEngine {
|
||||
* @param data 96 bytes minimum
|
||||
* @return null if decryption fails
|
||||
*/
|
||||
private CloveSet decryptNewSession(byte data[], PrivateKey targetPrivateKey)
|
||||
private CloveSet decryptNewSession(byte data[], PrivateKey targetPrivateKey, RatchetSKM keyManager)
|
||||
throws DataFormatException {
|
||||
HandshakeState state;
|
||||
try {
|
||||
@ -277,6 +274,11 @@ public final class ECIESAEADEngine {
|
||||
} catch (Exception e) {
|
||||
throw new DataFormatException("Msg 1 payload error", e);
|
||||
}
|
||||
|
||||
// tell the SKM
|
||||
PublicKey bob = new PublicKey(EncType.ECIES_X25519, bobPK);
|
||||
keyManager.createSession(bob, state);
|
||||
|
||||
if (pc.cloveSet.isEmpty()) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("No garlic block in NS payload");
|
||||
@ -309,7 +311,7 @@ public final class ECIESAEADEngine {
|
||||
* @param state must have already been cloned
|
||||
* @return null if decryption fails
|
||||
*/
|
||||
private CloveSet decryptNewSessionReply(byte[] tag, byte[] data, HandshakeState state)
|
||||
private CloveSet decryptNewSessionReply(byte[] tag, byte[] data, HandshakeState state, RatchetSKM keyManager)
|
||||
throws DataFormatException {
|
||||
// part 1 - handshake
|
||||
byte[] yy = new byte[KEYLEN];
|
||||
@ -370,8 +372,10 @@ public final class ECIESAEADEngine {
|
||||
} catch (Exception e) {
|
||||
throw new DataFormatException("NSR payload error", e);
|
||||
}
|
||||
RatchetTagSet tagset_ab = new RatchetTagSet(_hkdf, new SessionKey(ck), new SessionKey(k_ab), 0, 0);
|
||||
RatchetTagSet tagset_ba = new RatchetTagSet(_hkdf, null, new SessionKey(ck), new SessionKey(k_ba), 0, 0, 5, 5);
|
||||
long now = _context.clock().now();
|
||||
RatchetTagSet tagset_ab = new RatchetTagSet(_hkdf, new SessionKey(ck), new SessionKey(k_ab), now, 0);
|
||||
RatchetTagSet tagset_ba = new RatchetTagSet(_hkdf, keyManager, new SessionKey(ck), new SessionKey(k_ba), now, 0, 5, 5);
|
||||
// tell the SKM
|
||||
if (pc.cloveSet.isEmpty()) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("No garlic block in NSR payload");
|
||||
@ -516,13 +520,7 @@ public final class ECIESAEADEngine {
|
||||
_log.debug("Encrypting as NS to " + target);
|
||||
return encryptNewSession(cloves, target, priv, keyManager);
|
||||
}
|
||||
////
|
||||
byte[] tagsetkey = new byte[32];
|
||||
/*
|
||||
byte[] ck = state.getChainingKey();
|
||||
_hkdf.calculate(ck, ZEROLEN, INFO_0, tagsetkey);
|
||||
RatchetTagSet tagset = new RatchetTagSet(_context, new SessionKey(ck), new SessionKey(tagsetkey), 0, 0);
|
||||
*/
|
||||
|
||||
HandshakeState state = re.key.getHandshakeState();
|
||||
if (state != null) {
|
||||
try {
|
||||
@ -533,8 +531,12 @@ public final class ECIESAEADEngine {
|
||||
return null;
|
||||
}
|
||||
// register state with skm
|
||||
return encryptNewSessionReply(cloves, state, re.tag);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Encrypting as NSR to " + target + " with tag " + re.tag);
|
||||
return encryptNewSessionReply(cloves, state, re.tag, keyManager);
|
||||
}
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Encrypting as ES to " + target + " with key " + re.key + " and tag " + re.tag);
|
||||
byte rv[] = encryptExistingSession(cloves, target, re.key, re.tag);
|
||||
return rv;
|
||||
}
|
||||
@ -589,11 +591,8 @@ public final class ECIESAEADEngine {
|
||||
}
|
||||
eph.getEncodedPublicKey(enc, 0);
|
||||
|
||||
// save for tagset HKDF
|
||||
byte[] ck = state.getChainingKey();
|
||||
// register state with skm
|
||||
// keyManager.tagsDelivered(state);
|
||||
// todo
|
||||
// tell the SKM
|
||||
keyManager.createSession(target, state);
|
||||
return enc;
|
||||
}
|
||||
|
||||
@ -616,7 +615,8 @@ public final class ECIESAEADEngine {
|
||||
* @param state must have already been cloned
|
||||
* @return encrypted data or null on failure
|
||||
*/
|
||||
private byte[] encryptNewSessionReply(CloveSet cloves, HandshakeState state, RatchetSessionTag currentTag) {
|
||||
private byte[] encryptNewSessionReply(CloveSet cloves, HandshakeState state,
|
||||
RatchetSessionTag currentTag, RatchetSKM keyManager) {
|
||||
byte[] tag = currentTag.getData();
|
||||
state.mixHash(tag, 0, TAGLEN);
|
||||
|
||||
@ -666,9 +666,10 @@ public final class ECIESAEADEngine {
|
||||
_log.warn("Encrypt fail NSR part 2", gse);
|
||||
return null;
|
||||
}
|
||||
RatchetTagSet tagset_ab = new RatchetTagSet(_hkdf, new SessionKey(ck), new SessionKey(k_ab), 0, 0);
|
||||
/// lsnr
|
||||
RatchetTagSet tagset_ba = new RatchetTagSet(_hkdf, null, new SessionKey(ck), new SessionKey(k_ba), 0, 0, 5, 5);
|
||||
long now = _context.clock().now();
|
||||
RatchetTagSet tagset_ab = new RatchetTagSet(_hkdf, new SessionKey(ck), new SessionKey(k_ab), now, 0);
|
||||
RatchetTagSet tagset_ba = new RatchetTagSet(_hkdf, keyManager, new SessionKey(ck), new SessionKey(k_ba), now, 0, 5, 5);
|
||||
// tell the SKM
|
||||
|
||||
return enc;
|
||||
}
|
||||
@ -751,7 +752,7 @@ public final class ECIESAEADEngine {
|
||||
|
||||
public void gotGarlic(GarlicClove clove) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got GARLIC block");
|
||||
_log.debug("Got GARLIC block: " + clove);
|
||||
cloveSet.add(clove);
|
||||
}
|
||||
|
||||
|
@ -32,44 +32,48 @@ public class MuxedSKM extends SessionKeyManager {
|
||||
|
||||
public RatchetSKM getECSKM() { return _ec; }
|
||||
|
||||
/**
|
||||
* ElG only
|
||||
*/
|
||||
@Override
|
||||
public SessionKey getCurrentKey(PublicKey target) {
|
||||
EncType type = target.getType();
|
||||
if (type == EncType.ELGAMAL_2048)
|
||||
return _elg.getCurrentKey(target);
|
||||
if (type == EncType.ECIES_X25519)
|
||||
return _ec.getCurrentKey(target);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ElG only
|
||||
*/
|
||||
@Override
|
||||
public SessionKey getCurrentOrNewKey(PublicKey target) {
|
||||
EncType type = target.getType();
|
||||
if (type == EncType.ELGAMAL_2048)
|
||||
return _elg.getCurrentOrNewKey(target);
|
||||
if (type == EncType.ECIES_X25519)
|
||||
return _ec.getCurrentOrNewKey(target);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ElG only
|
||||
*/
|
||||
@Override
|
||||
public void createSession(PublicKey target, SessionKey key) {
|
||||
EncType type = target.getType();
|
||||
if (type == EncType.ELGAMAL_2048)
|
||||
_elg.createSession(target, key);
|
||||
else if (type == EncType.ECIES_X25519)
|
||||
_ec.createSession(target, key);
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
/**
|
||||
* ElG only
|
||||
*/
|
||||
@Override
|
||||
public SessionKey createSession(PublicKey target) {
|
||||
EncType type = target.getType();
|
||||
if (type == EncType.ELGAMAL_2048)
|
||||
return _elg.createSession(target);
|
||||
if (type == EncType.ECIES_X25519)
|
||||
return _ec.createSession(target);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -15,4 +15,9 @@ class RatchetEntry {
|
||||
this.tag = tag;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RatchetEntry[" + tag + ' ' + key + ']';
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ import net.i2p.util.SimpleTimer;
|
||||
public class RatchetSKM extends SessionKeyManager implements SessionTagListener {
|
||||
private final Log _log;
|
||||
/** Map allowing us to go from the targeted PublicKey to the OutboundSession used */
|
||||
private final Map<PublicKey, OutboundSession> _outboundSessions;
|
||||
private final ConcurrentHashMap<PublicKey, OutboundSession> _outboundSessions;
|
||||
/** Map allowing us to go from a SessionTag to the containing RatchetTagSet */
|
||||
private final ConcurrentHashMap<RatchetSessionTag, RatchetTagSet> _inboundTagSets;
|
||||
protected final I2PAppContext _context;
|
||||
@ -74,6 +74,8 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
private static final int MIN_RCV_WINDOW = 20;
|
||||
private static final int MAX_RCV_WINDOW = 50;
|
||||
|
||||
private static final byte[] ZEROLEN = new byte[0];
|
||||
private static final String INFO_0 = "SessionReplyTags";
|
||||
|
||||
|
||||
/**
|
||||
@ -86,7 +88,7 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
super(context);
|
||||
_log = context.logManager().getLog(RatchetSKM.class);
|
||||
_context = context;
|
||||
_outboundSessions = new HashMap<PublicKey, OutboundSession>(64);
|
||||
_outboundSessions = new ConcurrentHashMap<PublicKey, OutboundSession>(64);
|
||||
_inboundTagSets = new ConcurrentHashMap<RatchetSessionTag, RatchetTagSet>(128);
|
||||
_hkdf = new HKDF(context);
|
||||
// start the precalc of Elg2 keys if it wasn't already started
|
||||
@ -99,9 +101,7 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
public void shutdown() {
|
||||
_alive = false;
|
||||
_inboundTagSets.clear();
|
||||
synchronized (_outboundSessions) {
|
||||
_outboundSessions.clear();
|
||||
}
|
||||
_outboundSessions.clear();
|
||||
}
|
||||
|
||||
private class CleanupEvent implements SimpleTimer.TimedEvent {
|
||||
@ -123,84 +123,63 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
|
||||
/** OutboundSession - used only by HTML */
|
||||
private Set<OutboundSession> getOutboundSessions() {
|
||||
synchronized (_outboundSessions) {
|
||||
return new HashSet<OutboundSession>(_outboundSessions.values());
|
||||
}
|
||||
return new HashSet<OutboundSession>(_outboundSessions.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the session key currently associated with encryption to the target,
|
||||
* or null if a new session key should be generated.
|
||||
*
|
||||
* Warning - don't generate a new session if this returns null, it's racy, use getCurrentOrNewKey()
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
@Override
|
||||
public SessionKey getCurrentKey(PublicKey target) {
|
||||
OutboundSession sess = getSession(target);
|
||||
if (sess == null) return null;
|
||||
long now = _context.clock().now();
|
||||
if (sess.getLastUsedDate() < now - SESSION_LIFETIME_MAX_MS) {
|
||||
if (_log.shouldInfo())
|
||||
_log.info("Expiring old session key established on "
|
||||
+ new Date(sess.getEstablishedDate())
|
||||
+ " but not used for "
|
||||
+ (now-sess.getLastUsedDate())
|
||||
+ "ms with target " + toString(target));
|
||||
return null;
|
||||
}
|
||||
return sess.getCurrentKey();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the session key currently associated with encryption to the target.
|
||||
* Generates a new session and session key if not previously exising.
|
||||
*
|
||||
* @return non-null
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
@Override
|
||||
public SessionKey getCurrentOrNewKey(PublicKey target) {
|
||||
synchronized (_outboundSessions) {
|
||||
OutboundSession sess = _outboundSessions.get(target);
|
||||
if (sess != null) {
|
||||
long now = _context.clock().now();
|
||||
if (sess.getLastUsedDate() < now - SESSION_LIFETIME_MAX_MS)
|
||||
sess = null;
|
||||
}
|
||||
if (sess == null) {
|
||||
SessionKey key = _context.keyGenerator().generateSessionKey();
|
||||
createAndReturnSession(target, key);
|
||||
return key;
|
||||
}
|
||||
return sess.getCurrentKey();
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a new session key with the specified target. Metrics to determine
|
||||
* when to expire that key begin with this call.
|
||||
*
|
||||
* Racy if called after getCurrentKey() to check for a current session;
|
||||
* use getCurrentOrNewKey() in that case.
|
||||
* @throws UnsupportedOperationException always
|
||||
*/
|
||||
@Override
|
||||
public void createSession(PublicKey target, SessionKey key) {
|
||||
createAndReturnSession(target, key);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above but for internal use, returns OutboundSession so we don't have
|
||||
* to do a subsequent getSession()
|
||||
* Inbound or outbound. Checks state.getRole() to determine.
|
||||
* For outbound (NS sent), adds to list of pending inbound sessions and returns true.
|
||||
* For inbound (NS rcvd), if no other pending outbound sessions, creates one
|
||||
* and returns true, or false if one already exists.
|
||||
*
|
||||
*/
|
||||
private OutboundSession createAndReturnSession(PublicKey target, SessionKey key) {
|
||||
boolean createSession(PublicKey target, HandshakeState state) {
|
||||
EncType type = target.getType();
|
||||
if (type != EncType.ECIES_X25519)
|
||||
throw new IllegalArgumentException("Bad public key type " + type);
|
||||
if (_log.shouldInfo())
|
||||
_log.info("New OB session, sesskey: " + key + " target: " + toString(target));
|
||||
OutboundSession sess = new OutboundSession(_context, _log, target, key);
|
||||
addSession(sess);
|
||||
return sess;
|
||||
boolean isInbound = state.getRole() == HandshakeState.RESPONDER;
|
||||
if (isInbound) {
|
||||
// we are Bob, NS received
|
||||
OutboundSession sess = new OutboundSession(target, null, state);
|
||||
boolean rv = addSession(sess);
|
||||
if (_log.shouldInfo()) {
|
||||
if (rv)
|
||||
_log.info("New OB session as Bob. Alice: " + toString(target));
|
||||
else
|
||||
_log.info("Dup OB session as Bob. Alice: " + toString(target));
|
||||
}
|
||||
return rv;
|
||||
} else {
|
||||
// we are Alice, NS sent
|
||||
OutboundSession sess = new OutboundSession(target, null, state);
|
||||
if (_log.shouldInfo())
|
||||
_log.info("New OB session as Alice. Bob: " + toString(target));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,7 +211,14 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
_log.debug("No OB session to " + toString(target));
|
||||
return null;
|
||||
}
|
||||
return sess.consumeNext();
|
||||
RatchetEntry rv = sess.consumeNext();
|
||||
if (_log.shouldDebug()) {
|
||||
if (rv != null)
|
||||
_log.debug("Using next key/tag " + rv + " to " + toString(target));
|
||||
else
|
||||
_log.debug("No more tags in OB session to " + toString(target));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -314,7 +300,8 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
if (sess == null) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("No session for delivered RatchetTagSet to target: " + toString(target));
|
||||
sess = createAndReturnSession(target, key);
|
||||
///////////
|
||||
createSession(target, key);
|
||||
} else {
|
||||
sess.setCurrentKey(key);
|
||||
}
|
||||
@ -419,6 +406,8 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Inbound.
|
||||
*
|
||||
* Determine if we have received a session key associated with the given session tag,
|
||||
* and if so, discard it and return the decryption
|
||||
* key it was received with (via tagsReceived(...)). returns null if no session key
|
||||
@ -451,23 +440,21 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
}
|
||||
|
||||
private OutboundSession getSession(PublicKey target) {
|
||||
synchronized (_outboundSessions) {
|
||||
return _outboundSessions.get(target);
|
||||
}
|
||||
return _outboundSessions.get(target);
|
||||
}
|
||||
|
||||
private void addSession(OutboundSession sess) {
|
||||
synchronized (_outboundSessions) {
|
||||
_outboundSessions.put(sess.getTarget(), sess);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @return true if added
|
||||
*/
|
||||
private boolean addSession(OutboundSession sess) {
|
||||
OutboundSession old = _outboundSessions.putIfAbsent(sess.getTarget(), sess);
|
||||
return old == null;
|
||||
}
|
||||
|
||||
private void removeSession(PublicKey target) {
|
||||
if (target == null) return;
|
||||
OutboundSession session = null;
|
||||
synchronized (_outboundSessions) {
|
||||
session = _outboundSessions.remove(target);
|
||||
}
|
||||
OutboundSession session = _outboundSessions.remove(target);
|
||||
if ( (session != null) && (_log.shouldWarn()) )
|
||||
_log.warn("Removing session tags with " + session.availableTags() + " available for "
|
||||
+ (session.getLastExpirationDate()-_context.clock().now())
|
||||
@ -572,8 +559,11 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
buf.append("<tr class=\"debug_outboundtarget\"><td><div class=\"debug_targetinfo\"><b>Target public key:</b> ").append(toString(sess.getTarget())).append("<br>" +
|
||||
"<b>Established:</b> ").append(DataHelper.formatDuration2(now - sess.getEstablishedDate())).append(" ago<br>" +
|
||||
"<b>Ack Received?</b> ").append(sess.getAckReceived()).append("<br>" +
|
||||
"<b>Last Used:</b> ").append(DataHelper.formatDuration2(now - sess.getLastUsedDate())).append(" ago<br>" +
|
||||
"<b>Session key:</b> ").append(sess.getCurrentKey().toBase64()).append("</div></td>" +
|
||||
"<b>Last Used:</b> ").append(DataHelper.formatDuration2(now - sess.getLastUsedDate())).append(" ago<br>");
|
||||
SessionKey sk = sess.getCurrentKey();
|
||||
if (sk != null)
|
||||
buf.append("<b>Session key:</b> ").append(sk.toBase64());
|
||||
buf.append("</div></td>" +
|
||||
"<td><b># Sets:</b> ").append(sess.getTagSets().size()).append("</td></tr>" +
|
||||
"<tr><td colspan=\"2\"><ul>");
|
||||
for (Iterator<RatchetTagSet> siter = sets.iterator(); siter.hasNext();) {
|
||||
@ -621,9 +611,7 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
/**
|
||||
* The state for a crypto session to a single public key
|
||||
*/
|
||||
private static class OutboundSession {
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private class OutboundSession {
|
||||
private final PublicKey _target;
|
||||
private SessionKey _currentKey;
|
||||
private final long _established;
|
||||
@ -657,15 +645,37 @@ public class RatchetSKM extends SessionKeyManager implements SessionTagListener
|
||||
|
||||
private static final int MAX_FAILS = 2;
|
||||
|
||||
public OutboundSession(I2PAppContext ctx, Log log, PublicKey target, SessionKey key) {
|
||||
_context = ctx;
|
||||
_log = log;
|
||||
public OutboundSession(PublicKey target, SessionKey key, HandshakeState state) {
|
||||
_target = target;
|
||||
_currentKey = key;
|
||||
_established = ctx.clock().now();
|
||||
_established = _context.clock().now();
|
||||
_lastUsed = _established;
|
||||
_unackedTagSets = new HashSet<RatchetTagSet>(4);
|
||||
_tagSets = new ArrayList<RatchetTagSet>(6);
|
||||
// generate expected tagset
|
||||
byte[] ck = state.getChainingKey();
|
||||
byte[] tagsetkey = new byte[32];
|
||||
_hkdf.calculate(ck, ZEROLEN, INFO_0, tagsetkey);
|
||||
boolean isInbound = state.getRole() == HandshakeState.RESPONDER;
|
||||
SessionKey rk = new SessionKey(ck);
|
||||
SessionKey tk = new SessionKey(tagsetkey);
|
||||
if (isInbound) {
|
||||
// This is an INBOUND NS, we make an OUTBOUND tagset for the NSR
|
||||
RatchetTagSet tagset = new RatchetTagSet(_hkdf, state,
|
||||
rk, tk,
|
||||
_established, 0);
|
||||
_tagSets.add(tagset);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("New OB Session, rk = " + rk + " tk = " + tk + " 1st tagset: " + tagset);
|
||||
} else {
|
||||
// This is an OUTBOUND NS, we make an INBOUND tagset for the NSR
|
||||
RatchetTagSet tagset = new RatchetTagSet(_hkdf, RatchetSKM.this, state,
|
||||
rk, tk,
|
||||
_established, 0, 5, 5);
|
||||
_unackedTagSets.add(tagset);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("New IB Session, rk = " + rk + " tk = " + tk + " 1st tagset: " + tagset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,7 +60,17 @@ class RatchetTagSet implements TagSetHandle {
|
||||
private static final int TAGLEN = 8;
|
||||
|
||||
/**
|
||||
* Outbound Tagset
|
||||
* Outbound NSR Tagset
|
||||
*
|
||||
* @param date For outbound: creation time
|
||||
*/
|
||||
public RatchetTagSet(HKDF hkdf, HandshakeState state, SessionKey rootKey, SessionKey data,
|
||||
long date, int id) {
|
||||
this(hkdf, null, state, rootKey, data, date, id, false, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outbound ES Tagset
|
||||
*
|
||||
* @param date For outbound: creation time
|
||||
*/
|
||||
@ -125,8 +135,6 @@ class RatchetTagSet implements TagSetHandle {
|
||||
_sessionTags = null;
|
||||
_sessionKeys = null;
|
||||
}
|
||||
System.out.println("DH INIT, rootKey = " + rootKey.toBase64() +
|
||||
" data = " + data.toBase64());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
@ -296,6 +304,10 @@ class RatchetTagSet implements TagSetHandle {
|
||||
* @return a key and nonce, non-null
|
||||
*/
|
||||
public SessionKeyAndNonce consumeNextKey() {
|
||||
// NSR
|
||||
if (_state != null)
|
||||
return new SessionKeyAndNonce(_state);
|
||||
// ES
|
||||
byte[] key = new byte[32];
|
||||
hkdf.calculate(_symmkey_ck, _symmkey_constant, INFO_5, _symmkey_ck, key, 0);
|
||||
_lastKey++;
|
||||
@ -325,15 +337,19 @@ class RatchetTagSet implements TagSetHandle {
|
||||
buf.append(" Size: ").append(sz);
|
||||
buf.append('/').append(getOriginalSize());
|
||||
buf.append(" Acked? ").append(_acked);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
int n = _sessionTags.keyAt(i);
|
||||
RatchetSessionTag tag = _sessionTags.valueAt(i);
|
||||
byte[] key = _sessionKeys.get(n);
|
||||
buf.append("\n " + n + '\t' + Base64.encode(tag.getData()));
|
||||
if (key != null)
|
||||
buf.append('\t' + Base64.encode(key));
|
||||
else
|
||||
buf.append("\tdeferred");
|
||||
if (_sessionTags != null) {
|
||||
for (int i = 0; i < sz; i++) {
|
||||
int n = _sessionTags.keyAt(i);
|
||||
RatchetSessionTag tag = _sessionTags.valueAt(i);
|
||||
buf.append("\n " + n + '\t' + Base64.encode(tag.getData()));
|
||||
if (_sessionKeys != null) {
|
||||
byte[] key = _sessionKeys.get(n);
|
||||
if (key != null)
|
||||
buf.append('\t' + Base64.encode(key));
|
||||
else
|
||||
buf.append("\tdeferred");
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
Reference in New Issue
Block a user