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 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 (GarlicAESBlock, I2PSessionKey) RetrieveAESBlock( GarlicMessage garlic, I2PPrivateKey privatekey, Func <I2PSessionTag, I2PSessionKey> findsessionkey) { GarlicAESBlock result; var cipher = new CbcBlockCipher(new AesEngine()); var tag = new I2PSessionTag(new BufRefLen(garlic.EGData, 0, 32)); var sessionkey = findsessionkey?.Invoke(tag); #if LOG_ALL_LEASE_MGMT Logging.LogDebug($"Garlic: Session key found {sessionkey}"); #endif if (sessionkey != null) { var aesbuf = new BufLen(garlic.EGData, 32); var pivh = I2PHashSHA256.GetHash(tag.Value); cipher.Init(false, sessionkey.Key.ToParametersWithIV(new BufLen(pivh, 0, 16))); cipher.ProcessBytes(aesbuf); try { result = new GarlicAESBlock(new BufRefLen(aesbuf)); if (!result.VerifyPayloadHash()) { Logging.LogDebug("Garlic: DecryptMessage: AES block SHA256 check failed."); return(null, null); } return(result, sessionkey); } catch (ArgumentException ex) { Logging.Log("Garlic", ex); } catch (Exception ex) { Logging.Log("Garlic", ex); return(null, null); } } #if LOG_ALL_LEASE_MGMT Logging.LogDebug("Garlic: No session key. Using ElGamal to decrypt."); #endif try { (result, sessionkey) = Garlic.EGDecryptGarlic(garlic, privatekey); #if LOG_ALL_LEASE_MGMT Logging.LogDebug($"Garlic: EG session key {sessionkey}"); #endif } catch (Exception ex) { Logging.LogDebug("Garlic: ElGamal DecryptMessage failed"); Logging.LogDebugData($"ReceivedSessions {ex}"); return(null, null); } return(result, sessionkey); }
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)); }