void UpdateCachedFields(BufRef reader) { CachedKey = new I2PIdentHash(reader); CachedFrom = new I2PIdentHash(reader); CachedLookupType = (LookupTypes)reader.Read8(); if (((byte)CachedLookupType & 0x01) != 0) { CachedTunnelId = new I2PTunnelId(reader); } var excludecount = reader.ReadFlip16(); for (int i = 0; i < excludecount; ++i) { CachedExcludeList.Add(new DatabaseSearchReplyMessage(reader)); } if (((byte)CachedLookupType & 0x02) != 0) { CachedReplyKey = new I2PSessionKey(reader); var tagcount = reader.Read8(); CachedTags.Add(new I2PSessionTag(reader)); } }
public static GarlicMessage AESEncryptGarlic( Garlic msg, I2PSessionKey sessionkey, I2PSessionTag tag, List <I2PSessionTag> newtags) { var cipher = new CbcBlockCipher(new AesEngine()); var payload = msg.ToByteArray(); var dest = new BufLen(new byte[65536]); // Reserve header + 4 bytes for GarlicMessageLength var writer = new BufRefLen(dest, I2NPMaxHeaderSize + 4); // Tag as header writer.Write(tag.Value); // AES block var aesstart = new BufLen(writer); var aesblock = new GarlicAESBlock(writer, newtags, 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), I2NPMaxHeaderSize); return(new GarlicMessage(new BufRefLen(dest, I2NPMaxHeaderSize, length))); }
public static (GarlicAESBlock, I2PSessionKey) EGDecryptGarlic( GarlicMessage garlic, I2PPrivateKey privkey) { var cipher = new CbcBlockCipher(new AesEngine()); var egdata = garlic.EGData; var egbuf = new BufLen(egdata, 0, 514); var egheader = ElGamalCrypto.Decrypt(egbuf, privkey, true); var sessionkey = new I2PSessionKey(new BufLen(egheader, 0, 32)); var preiv = new BufLen(egheader, 32, 32); var egpadding = new BufLen(egheader, 64, 158); var 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 = new GarlicAESBlock(new BufRefLen(aesbuf)); if (!aesblock.VerifyPayloadHash()) { throw new ChecksumFailureException("AES block hash check failed!"); } return(aesblock, sessionkey); }
public GarlicCloveDeliveryLocal(BufRef reader, byte flag) : base(DeliveryMethod.Local) { Flag = flag; if ((Flag & (byte)DeliveryFlags.Encrypted) != 0) { SessionKey = new I2PSessionKey(reader); } if ((Flag & (byte)DeliveryFlags.Delay) != 0) { Delay = reader.ReadFlip32(); } }
public GarlicCloveDeliveryRouter(BufRef reader, byte flag) : base(DeliveryMethod.Router) { Flag = flag; if ((Flag & (byte)DeliveryFlags.Encrypted) != 0) { SessionKey = new I2PSessionKey(reader); } Destination = new I2PIdentHash(reader); if ((Flag & (byte)DeliveryFlags.Delay) != 0) { Delay = reader.ReadFlip32(); } }
public GarlicAESBlock( BufRefLen reader, IList <I2PSessionTag> tags, I2PSessionKey newsessionkey, BufRefLen payload) { var start = new BufLen(reader); // Allocate TagCount = reader.ReadBufLen(2); if (tags != null) { for (int i = 0; i < tags.Count; ++i) { Tags.Add(reader.ReadBufLen(I2PSessionTag.TagLength)); } } PayloadSize = reader.ReadBufLen(4); PayloadHash = reader.ReadBufLen(32); Flag = reader.ReadBufLen(1); if (newsessionkey != null) { reader.ReadBufLen(32); } var pllen = Math.Min(reader.Length, payload.Length); Payload = reader.ReadBufLen(pllen); Padding = reader.ReadBufLen(BufUtils.Get16BytePadding(reader - start)); // Write TagCount.PokeFlip16((ushort)(tags == null ? 0 : tags.Count), 0); if (tags != null) { for (int i = 0; i < tags.Count; ++i) { Tags[i].Poke(tags[i].Value, 0); } } Flag[0] = (byte)(newsessionkey != null ? 0x01 : 0); if (newsessionkey != null) { NewSessionKey.Poke(newsessionkey.Key, 0); } Payload.Poke(new BufLen(payload, 0, pllen), 0); payload.Seek(pllen); PayloadSize.PokeFlip32((uint)pllen, 0); PayloadHash.Poke(I2PHashSHA256.GetHash(Payload), 0); Padding.Randomize(); DataBuf = new BufLen(start, 0, reader - start); }
public void TestEncodeDecodeAES() { var m1 = new DeliveryStatusMessage(0x4321); var m2 = new DeliveryStatusMessage(0xa3c2); var garlic = new Garlic( new GarlicClove( new GarlicCloveDeliveryDestination( m1, Destination.IdentHash)), new GarlicClove( new GarlicCloveDeliveryDestination( m2, Destination.IdentHash)) ); // No tags var sessionkey = new I2PSessionKey(); var sessiontag = new I2PSessionTag(); var cg = Garlic.AESEncryptGarlic(garlic, sessionkey, sessiontag, null); var egdata = I2NPMessage.Clone(cg); var(aesblock, sk) = Garlic.RetrieveAESBlock(egdata, Private, (t) => sessionkey); var g2 = new Garlic((BufRefLen)aesblock.Payload); Assert.IsTrue(BufUtils.Equal(garlic.ToByteArray(), g2.ToByteArray())); // With tags var tags = new List <I2PSessionTag>(); for (int i = 0; i < 30; ++i) { tags.Add(new I2PSessionTag()); } cg = Garlic.AESEncryptGarlic(garlic, sessionkey, sessiontag, null); egdata = I2NPMessage.Clone(cg); (aesblock, sk) = Garlic.RetrieveAESBlock(egdata, Private, (t) => sessionkey); g2 = new Garlic((BufRefLen)aesblock.Payload); Assert.IsTrue(BufUtils.Equal(garlic.ToByteArray(), g2.ToByteArray())); }
public static GarlicMessage EGEncryptGarlic( Garlic msg, I2PPublicKey pubkey, I2PSessionKey sessionkey, List <I2PSessionTag> newtags) { var cipher = new CbcBlockCipher(new AesEngine()); var payload = msg.ToByteArray(); var dest = new BufLen(new byte[65536]); // Reserve header + 4 bytes for GarlicMessageLength var writer = new BufRefLen(dest, I2NPMaxHeaderSize + 4); // ElGamal block var egbuf = new BufLen(new byte[222]); var sessionkeybuf = new BufLen(egbuf, 0, 32); var preivbuf = new BufLen(egbuf, 32, 32); var egpadding = new BufLen(egbuf, 64, 158); egpadding.Randomize(); preivbuf.Randomize(); sessionkeybuf.Poke(sessionkey.Key, 0); var iv = new BufLen(I2PHashSHA256.GetHash(preivbuf), 0, 16); ElGamalCrypto.Encrypt(writer, egbuf, pubkey, true); // AES block var aesstart = new BufLen(writer); var aesblock = new GarlicAESBlock(writer, newtags, null, new BufRefLen(payload)); cipher.Init(true, sessionkey.Key.ToParametersWithIV(iv)); cipher.ProcessBytes(aesblock.DataBuf); var length = writer - dest; dest.PokeFlip32((uint)(length - 4), I2NPMaxHeaderSize); return(new GarlicMessage(new BufRefLen(dest, I2NPMaxHeaderSize, length))); }
public GarlicAESBlock(BufRefLen reader) { var start = new BufLen(reader); TagCount = reader.ReadBufLen(2); var tags = TagCount.PeekFlip16(0); if (tags > 0) { if (tags * I2PSessionTag.TagLength > start.Length) { throw new ArgumentException("GarlicAESBlock: Not enough data for the tags supplied."); } for (int i = 0; i < tags; ++i) { Tags.Add(reader.ReadBufLen(I2PSessionTag.TagLength)); } } PayloadSize = reader.ReadBufLen(4); PayloadHash = reader.ReadBufLen(32); Flag = reader.ReadBufLen(1); if (Flag[0] != 0) { NewSessionKey = new I2PSessionKey(reader.ReadBufLen(32)); } var pllen = PayloadSize.PeekFlip32(0); if (pllen > reader.Length) { throw new ArgumentException("GarlicAESBlock: Not enough data payload supplied."); } Payload = reader.ReadBufLen((int)pllen); Padding = reader.ReadBufLen(BufUtils.Get16BytePadding(reader - start)); DataBuf = new BufLen(start, 0, reader - start); }
public void Reset() { SessionKey = new I2PSessionKey(); lock (SessionTags) SessionTags.Clear(); }
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)); }