You've already forked lidgren-network-gen3
mirror of
https://github.com/lidgren/lidgren-network-gen3.git
synced 2026-05-16 15:16:33 +09:00
Net encryption generalized to support more algorithms
This commit is contained in:
14
Lidgren.Network/Encryption/INetEncryption.cs
Normal file
14
Lidgren.Network/Encryption/INetEncryption.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Lidgren.Network
|
||||
{
|
||||
public interface INetEncryption
|
||||
{
|
||||
bool Encrypt(NetOutgoingMessage msg);
|
||||
bool Decrypt(NetIncomingMessage msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
78
Lidgren.Network/Encryption/NetBlockEncryptionBase.cs
Normal file
78
Lidgren.Network/Encryption/NetBlockEncryptionBase.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Lidgren.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Base for a non-threadsafe encryption class
|
||||
/// </summary>
|
||||
public abstract class NetBlockEncryptionBase : INetEncryption
|
||||
{
|
||||
// temporary space for one block to avoid reallocating every time
|
||||
private byte[] m_tmp;
|
||||
|
||||
/// <summary>
|
||||
/// Block size in bytes for this cipher
|
||||
/// </summary>
|
||||
public abstract int BlockSize { get; }
|
||||
|
||||
public NetBlockEncryptionBase()
|
||||
{
|
||||
m_tmp = new byte[BlockSize];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypt am outgoing message with this algorithm; no writing can be done to the message after encryption, or message will be corrupted
|
||||
/// </summary>
|
||||
public bool Encrypt(NetOutgoingMessage msg)
|
||||
{
|
||||
int payloadBitLength = msg.LengthBits;
|
||||
int numBytes = msg.LengthBytes;
|
||||
int blockSize = BlockSize;
|
||||
int numBlocks = (int)Math.Ceiling((double)numBytes / (double)blockSize);
|
||||
int dstSize = numBlocks * blockSize;
|
||||
|
||||
msg.EnsureBufferSize(dstSize * 8 + 2); // add 2 bytes for payload length at end
|
||||
msg.LengthBits = dstSize * 8; // length will automatically adjust +4 bytes when payload length is written
|
||||
|
||||
for(int i=0;i<numBlocks;i++)
|
||||
{
|
||||
EncryptBlock(msg.m_data, (i * blockSize), m_tmp);
|
||||
Buffer.BlockCopy(m_tmp, 0, msg.m_data, (i * blockSize), m_tmp.Length);
|
||||
}
|
||||
|
||||
// add true payload length last
|
||||
msg.Write((ushort)payloadBitLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrypt an incoming message encrypted with corresponding Encrypt
|
||||
/// </summary>
|
||||
/// <param name="msg">message to decrypt</param>
|
||||
/// <returns>true if successful; false if failed</returns>
|
||||
public bool Decrypt(NetIncomingMessage msg)
|
||||
{
|
||||
int numEncryptedBytes = msg.LengthBytes - 2; // last 2 bytes is true bit length
|
||||
int blockSize = BlockSize;
|
||||
int numBlocks = numEncryptedBytes / blockSize;
|
||||
if (numBlocks * blockSize != numEncryptedBytes)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
{
|
||||
DecryptBlock(msg.m_data, (i * blockSize), m_tmp);
|
||||
Buffer.BlockCopy(m_tmp, 0, msg.m_data, (i * blockSize), m_tmp.Length);
|
||||
}
|
||||
|
||||
// read 16 bits of true payload length
|
||||
uint realSize = NetBitWriter.ReadUInt32(msg.m_data, 16, (numEncryptedBytes * 8));
|
||||
msg.m_bitLength = (int)realSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void EncryptBlock(byte[] source, int sourceOffset, byte[] destination);
|
||||
protected abstract void DecryptBlock(byte[] source, int sourceOffset, byte[] destination);
|
||||
}
|
||||
}
|
||||
46
Lidgren.Network/Encryption/NetXorEncryption.cs
Normal file
46
Lidgren.Network/Encryption/NetXorEncryption.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Lidgren.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Example class; not very good encryption
|
||||
/// </summary>
|
||||
public class NetXorEncryption : INetEncryption
|
||||
{
|
||||
private byte[] m_key;
|
||||
|
||||
public NetXorEncryption(byte[] key)
|
||||
{
|
||||
m_key = key;
|
||||
}
|
||||
|
||||
public NetXorEncryption(string key)
|
||||
{
|
||||
m_key = Encoding.ASCII.GetBytes(key);
|
||||
}
|
||||
|
||||
public bool Encrypt(NetOutgoingMessage msg)
|
||||
{
|
||||
int numBytes = msg.LengthBytes;
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
{
|
||||
int offset = i % m_key.Length;
|
||||
msg.m_data[i] = (byte)(msg.m_data[i] ^ m_key[offset]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Decrypt(NetIncomingMessage msg)
|
||||
{
|
||||
int numBytes = msg.LengthBytes;
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
{
|
||||
int offset = i % m_key.Length;
|
||||
msg.m_data[i] = (byte)(msg.m_data[i] ^ m_key[offset]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
137
Lidgren.Network/Encryption/NetXteaEncryption.cs
Normal file
137
Lidgren.Network/Encryption/NetXteaEncryption.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
/* Copyright (c) 2010 Michael Lidgren
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
and associated documentation files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Security;
|
||||
|
||||
namespace Lidgren.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Methods to encrypt and decrypt data using the XTEA algorithm
|
||||
/// </summary>
|
||||
public sealed class NetXtea : NetBlockEncryptionBase
|
||||
{
|
||||
private const int c_blockSize = 8;
|
||||
private const int c_keySize = 16;
|
||||
private const int c_delta = unchecked((int)0x9E3779B9);
|
||||
|
||||
private readonly int m_numRounds;
|
||||
private readonly uint[] m_sum0;
|
||||
private readonly uint[] m_sum1;
|
||||
|
||||
public override int BlockSize { get { return c_blockSize; } }
|
||||
|
||||
/// <summary>
|
||||
/// 16 byte key
|
||||
/// </summary>
|
||||
public NetXtea(byte[] key, int rounds)
|
||||
{
|
||||
if (key.Length < c_keySize)
|
||||
throw new NetException("Key too short!");
|
||||
|
||||
m_numRounds = rounds;
|
||||
m_sum0 = new uint[m_numRounds];
|
||||
m_sum1 = new uint[m_numRounds];
|
||||
uint[] tmp = new uint[8];
|
||||
|
||||
int num2;
|
||||
int index = num2 = 0;
|
||||
while (index < 4)
|
||||
{
|
||||
tmp[index] = BitConverter.ToUInt32(key, num2);
|
||||
index++;
|
||||
num2 += 4;
|
||||
}
|
||||
for (index = num2 = 0; index < 32; index++)
|
||||
{
|
||||
m_sum0[index] = ((uint)num2) + tmp[num2 & 3];
|
||||
num2 += -1640531527;
|
||||
m_sum1[index] = ((uint)num2) + tmp[(num2 >> 11) & 3];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 16 byte key
|
||||
/// </summary>
|
||||
public NetXtea(byte[] key)
|
||||
: this(key, 32)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String to hash for key
|
||||
/// </summary>
|
||||
public NetXtea(string key)
|
||||
: this(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key)), 32)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void EncryptBlock(byte[] source, int sourceOffset, byte[] destination)
|
||||
{
|
||||
uint v0 = BytesToUInt(source, sourceOffset);
|
||||
uint v1 = BytesToUInt(source, sourceOffset + 4);
|
||||
|
||||
for (int i = 0; i != m_numRounds; i++)
|
||||
{
|
||||
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ m_sum0[i];
|
||||
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ m_sum1[i];
|
||||
}
|
||||
|
||||
UIntToBytes(v0, destination, 0);
|
||||
UIntToBytes(v1, destination, 0 + 4);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
protected override void DecryptBlock(byte[] source, int sourceOffset, byte[] destination)
|
||||
{
|
||||
// Pack bytes into integers
|
||||
uint v0 = BytesToUInt(source, sourceOffset);
|
||||
uint v1 = BytesToUInt(source, sourceOffset + 4);
|
||||
|
||||
for (int i = m_numRounds - 1; i >= 0; i--)
|
||||
{
|
||||
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ m_sum1[i];
|
||||
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ m_sum0[i];
|
||||
}
|
||||
|
||||
UIntToBytes(v0, destination, 0);
|
||||
UIntToBytes(v1, destination, 0 + 4);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private static uint BytesToUInt(byte[] bytes, int offset)
|
||||
{
|
||||
uint retval = (uint)(bytes[offset] << 24);
|
||||
retval |= (uint)(bytes[++offset] << 16);
|
||||
retval |= (uint)(bytes[++offset] << 8);
|
||||
return (retval | bytes[++offset]);
|
||||
}
|
||||
|
||||
private static void UIntToBytes(uint value, byte[] destination, int destinationOffset)
|
||||
{
|
||||
destination[destinationOffset++] = (byte)(value >> 24);
|
||||
destination[destinationOffset++] = (byte)(value >> 16);
|
||||
destination[destinationOffset++] = (byte)(value >> 8);
|
||||
destination[destinationOffset++] = (byte)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user