Example #1
0
        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);
            }
        }
Example #2
0
        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));
        }
Example #3
0
        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));
        }
Example #4
0
        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));
        }