public void TestAESBlock() { for (int runs = 0; runs < 10; ++runs) { var buf = new BufLen(new byte[30000]); var writer = new BufRefLen(buf); var data = BufUtils.RandomBytes(1 + BufUtils.RandomInt(45)); var datar = new BufRefLen(data); var tags = new List <I2PSessionTag>(); for (int i = 0; i < BufUtils.RandomInt(5); ++i) { tags.Add(new I2PSessionTag()); } var newsession = BufUtils.RandomDouble(1.0) < 0.3 ? new I2PSessionKey() : null; var b1 = new GarlicAESBlock(writer, tags, newsession, datar); var bldata = new BufLen(buf, 0, writer - buf).Clone(); var b2 = new GarlicAESBlock(new BufRefLen(bldata)); var b1ar = new BufLen(b1.ToByteArray()); var b2ar = new BufLen(b2.ToByteArray()); Assert.IsTrue(b1ar == b2ar); var bufs = new BufRefStream(); b1.Write(bufs); var b3 = new GarlicAESBlock(new BufRefLen(bufs.ToByteArray())); var b3ar = new BufLen(b3.ToByteArray()); Assert.IsTrue(b1ar == b3ar); } }
GarlicCreationInfo UseExistingSessionTags(bool explack, uint trackingid, GarlicCloveDelivery[] cloves) { Garlic msg; DeliveryStatusMessage ackmsg = null; if (explack) { msg = AddExplAck(cloves, out ackmsg); } else { var exp = new I2PDate(DateTime.UtcNow.AddMinutes(5)); msg = new Garlic(cloves.Select(d => new GarlicClove(d, exp)).ToArray()); } #if LOG_ALL_TUNNEL_TRANSFER Logging.LogDebug(() => string.Format( "DestinationSession: Garlic generated with {0} cloves. {1} tags available.", msg.Cloves.Count, SessionTags.Count)); #endif var payload = msg.ToByteArray(); var dest = new BufLen(new byte[61000]); var writer = new BufRefLen(dest, 4); // Reserve 4 bytes for GarlicMessageLength I2PSessionTag tag; lock ( SessionTags ) { var ix = BufUtils.RandomInt(SessionTags.Count); tag = SessionTags[ix]; SessionTags.RemoveAt(ix); } // Tag as header writer.Write(tag.Value); // AES block var aesstart = new BufLen(writer); var aesblock = new GarlicAESBlock(writer, null, null, new BufRefLen(payload)); var pivh = I2PHashSHA256.GetHash(tag.Value); Cipher.Init(true, SessionKey.Key.ToParametersWithIV(new BufLen(pivh, 0, 16))); Cipher.ProcessBytes(aesblock.DataBuf); var length = writer - dest; dest.PokeFlip32((uint)(length - 4), 0); return(new GarlicCreationInfo( Destination.IdentHash, cloves, new EGGarlic(new BufRefLen(dest, 0, length)), GarlicCreationInfo.KeyUsed.Aes, SessionTags.Count(), trackingid, explack ? (uint?)ackmsg.MessageId : null, LatestEGAckMessageId)); }
GarlicCreationInfo GenerateNewSessionTags(uint trackingid, GarlicCloveDelivery[] cloves) { var newtags = new List <I2PSessionTag>(); for (int i = 0; i < 50; ++i) { newtags.Add(new I2PSessionTag()); } lock ( SessionTags ) { SessionTags.AddRange(newtags); } // Add a ACK message DeliveryStatusMessage ackmsg; var msg = AddExplAck(cloves, out ackmsg); var payload = msg.ToByteArray(); var dest = new BufLen(new byte[61000]); var writer = new BufRefLen(dest, 4); // Reserve 4 bytes for GarlicMessageLength // ElGamal block var egbuf = new BufLen(writer, 0, 222); var sessionkeybuf = new BufLen(egbuf, 0, 32); var preivbuf = new BufLen(egbuf, 32, 32); var egpadding = new BufLen(egbuf, 64); sessionkeybuf.Poke(SessionKey.Key, 0); preivbuf.Randomize(); egpadding.Randomize(); var preiv = preivbuf.Clone(); var eg = new ElGamalCrypto(Destination.PublicKey); eg.Encrypt(writer, egbuf, true); // AES block var aesstart = new BufLen(writer); var aesblock = new GarlicAESBlock(writer, newtags, null, new BufRefLen(payload)); var pivh = I2PHashSHA256.GetHash(preiv); Cipher.Init(true, SessionKey.Key.ToParametersWithIV(new BufLen(pivh, 0, 16))); Cipher.ProcessBytes(aesblock.DataBuf); var length = writer - dest; dest.PokeFlip32((uint)(length - 4), 0); LatestEGAckMessageId = ackmsg.MessageId; #if LOG_ALL_TUNNEL_TRANSFER Logging.LogDebug(() => string.Format( "DestinationSession: Garlic generated with ElGamal encryption, {0} cloves. {1} tags available. Ack MessageId: {2}.", msg.Cloves.Count, SessionTags.Count, LatestEGAckMessageId)); #endif return(new GarlicCreationInfo( Destination.IdentHash, cloves, new EGGarlic(new BufRefLen(dest, 0, length)), GarlicCreationInfo.KeyUsed.ElGamal, SessionTags.Count(), trackingid, ackmsg.MessageId, LatestEGAckMessageId)); }
public Garlic DecryptMessage(EGGarlic message) { lock ( SessionTags ) { var old = SessionTags.Where(p => p.Key.Created.DeltaToNow.ToMinutes > (I2PSessionTag.TagLifetimeMinutes + 2)).ToArray(); foreach (var one in old) { SessionTags.Remove(one.Key); } } var egdata = message.EGData; var tag = new I2PSessionTag(new BufRefLen(egdata, 0, 32)); I2PSessionKey sessionkey; bool found; lock ( SessionTags ) { found = SessionTags.TryGetValue(tag, out sessionkey); } BufLen aesbuf; if (found) { aesbuf = new BufLen(egdata, 32); lock ( SessionTags ) { SessionTags.Remove(tag); } #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug("ReceivedSessions: Working tag found for EGarlic."); #endif var pivh = I2PHashSHA256.GetHash(tag.Value); Cipher.Init(false, sessionkey.Key.ToParametersWithIV(new BufLen(pivh, 0, 16))); Cipher.ProcessBytes(aesbuf); } else { BufLen egheader; try { var egbuf = new BufLen(egdata, 0, 514); egheader = ElGamalCrypto.Decrypt(egbuf, Key, true); } catch (Exception ex) { DebugUtils.Log("ReceivedSessions", ex); return(null); } #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug("ReceivedSessions: Using ElGamal to decrypt."); #endif sessionkey = new I2PSessionKey(new BufLen(egheader, 0, 32)); var preiv = new BufLen(egheader, 32, 32); var egpadding = new BufLen(egheader, 64); aesbuf = new BufLen(egdata, 514); var pivh = I2PHashSHA256.GetHash(preiv); Cipher.Init(false, sessionkey.Key.ToParametersWithIV(new BufLen(pivh, 0, 16))); Cipher.ProcessBytes(aesbuf); } GarlicAESBlock aesblock; try { aesblock = new GarlicAESBlock(new BufRefLen(aesbuf)); } catch (Exception ex) { DebugUtils.Log("ReceivedSessions", ex); return(null); } if (!aesblock.VerifyPayloadHash()) { DebugUtils.LogDebug("ReceivedSessions: DecryptMessage: AES block SHA256 check failed."); return(null); } #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug("ReceivedSessions: Working Aes block received. " + SessionTags.Count.ToString() + " tags available."); #endif if (aesblock.Tags.Count > 0) { #if LOG_ALL_TUNNEL_TRANSFER DebugUtils.LogDebug("ReceivedSessions: " + aesblock.Tags.Count.ToString() + " new tags received."); #endif lock ( SessionTags ) { foreach (var onetag in aesblock.Tags.ToArray()) { SessionTags[new I2PSessionTag(new BufRef(onetag))] = sessionkey; } } } return(new Garlic((BufRefLen)aesblock.Payload)); }