If you use this class in your projects, please mention who is the autor... Thanks.
Code:
// * ***************************************
// * _ _ _
// * | | (_) |
// * | | ___ __ _ _| | __
// * | | / _ \ / _` | | |/ /
// * | |___| (_) | (_| | | < _
// * \_____/\___/ \__, |_|_|\_(_)
// * __/ |
// * |___/
// *
// * Copyright (C) 2010 - 2011
// *
// * ***************************************
// * CREDITS
// * ***************************************
// * Originally created by CptSky @ e*pvp, Copyright (C) 2010-2011,
// * Logik, All rights reserved.
// *
// * ***************************************
// * SPECIAL THANKS
// * ***************************************
// * Sparkie (Unknownone @ e*pvp)
// *
// * ***************************************
using System;
using System.Security.Cryptography;
namespace Logik.Security.Cryptography
{
/// <summary>
/// Conquer Online Server Asymmetric Cipher
/// </summary>
public class COSAC : AsymmetricAlgorithm
{
const Int32 COSAC_KEY_SIZE = 4096;
protected Byte[] IVValue;
protected Byte[] KeyValue;
protected UInt16 EncryptCounter;
protected UInt16 DecryptCounter;
protected String KeyExchangeAlgorithmValue;
protected String SignatureAlgorithmValue;
/// <summary>
/// Create a new COSAC instance with a key size of 4096.
/// </summary>
public COSAC()
: base()
{
this.KeyExchangeAlgorithmValue = "TQ_DIGITAL_CONQUER_ONLINE_KEY_EXCHANGE_ALGORITHM";
this.SignatureAlgorithmValue = "TQ_DIGITAL_CONQUER_ONLINE_SERVER_ASYMMETRIC_CIPHER";
this.LegalKeySizesValue = new KeySizes[] { new KeySizes(COSAC_KEY_SIZE, COSAC_KEY_SIZE, 0) };
this.KeySizeValue = COSAC_KEY_SIZE;
}
~COSAC()
{
KeyValue = null;
IVValue = null;
KeyExchangeAlgorithmValue = null;
SignatureAlgorithmValue = null;
}
/// <summary>
/// Releases the unmanaged resources used by the AsymmetricAlgorithm class and optionally releases the managed resources.
/// </summary>
protected override void Dispose(Boolean disposing)
{
Clear();
if (disposing)
{
KeyValue = null;
IVValue = null;
KeyExchangeAlgorithmValue = null;
SignatureAlgorithmValue = null;
}
}
/// <summary>
/// Reconstructs an AsymmetricAlgorithm object from an XML string. (Not Implemented!)
/// </summary>
public override void FromXmlString(String xmlString) { throw new NotImplementedException(); }
/// <summary>
/// Creates and returns an XML string representation of the current AsymmetricAlgorithm object. (Not Implemented!)
/// </summary>
public override String ToXmlString(Boolean includePrivateParameters) { throw new NotImplementedException(); }
/// <summary>
/// Gets the name of the key exchange algorithm.
/// </summary>
public override String KeyExchangeAlgorithm { get { return KeyExchangeAlgorithmValue; } }
/// <summary>
/// Gets the size, in bits, of the key modulus used by the asymmetric algorithm.
/// </summary>
public override Int32 KeySize { get { return base.KeySize; } }
/// <summary>
/// Gets the key sizes that are supported by the asymmetric algorithm.
/// </summary>
public override KeySizes[] LegalKeySizes { get { return base.LegalKeySizes; } }
/// <summary>
/// Gets the name of the signature algorithm.
/// </summary>
public override String SignatureAlgorithm { get { return SignatureAlgorithmValue; } }
/// <summary>
/// Generates an initialization vector (IV) to use for the algorithm.
/// CO2(P: 0x13FA0F9D, G: 0x6D5C7962)
/// </summary>
public void GenerateIV(Int32 P, Int32 G)
{
IVValue = new Byte[COSAC_KEY_SIZE / 8];
Int16 K = COSAC_KEY_SIZE / 16;
Byte[] PArray = new Byte[4] { (Byte)(P), (Byte)(P >> 8), (Byte)(P >> 16), (Byte)(P >> 24) };
Byte[] GArray = new Byte[4] { (Byte)(G), (Byte)(G >> 8), (Byte)(G >> 16), (Byte)(G >> 24) };
for (Int16 i = 0; i < K; i++)
{
IVValue[i + 0] = PArray[0];
IVValue[i + K] = GArray[0];
PArray[0] = (Byte)((PArray[1] + (Byte)(PArray[0] * PArray[2])) * PArray[0] + PArray[3]);
GArray[0] = (Byte)((GArray[1] - (Byte)(GArray[0] * GArray[2])) * GArray[0] + GArray[3]);
}
}
/// <summary>
/// Generates a key (Key) to use for the algorithm and reset the encrypt counter.
/// In Conquer Online: A = Token, B = AccountUID
/// </summary>
public void GenerateKey(Int32 A, Int32 B)
{
if (IVValue == null)
throw new NullReferenceException("IV needs to be generated before generating the key!");
KeyValue = new Byte[COSAC_KEY_SIZE / 8];
Int16 K = COSAC_KEY_SIZE / 16;
UInt32 tmp = 0;
tmp = (UInt32)(A + B);
Byte[] tmpKey1 = new Byte[4] { (Byte)(tmp >> 24), (Byte)(tmp >> 16), (Byte)(tmp >> 8), (Byte)(tmp) };
tmpKey1[2] ^= 0x43;
tmpKey1[3] ^= 0x21;
for (SByte i = 0; i < 4; i++)
tmpKey1[i] ^= (Byte)(A >> (24 - (8 * i)));
tmp = (UInt32)((tmpKey1[0] << 24) + (tmpKey1[1] << 16) + (tmpKey1[2] << 8) + tmpKey1[3]);
tmp *= tmp;
Byte[] tmpKey2 = new Byte[4] { (Byte)(tmp >> 24), (Byte)(tmp >> 16), (Byte)(tmp >> 8), (Byte)(tmp) };
for (Int16 i = 0; i < K; i++)
{
KeyValue[i + 0] = (Byte)(IVValue[i + 0] ^ tmpKey1[3 - (i % 4)]);
KeyValue[i + K] = (Byte)(IVValue[i + K] ^ tmpKey2[3 - (i % 4)]);
}
EncryptCounter = 0;
}
/// <summary>
/// Decrypts data with the COSAC algorithm.
/// </summary>
public void Decrypt(ref Byte[] rgb)
{
if (rgb == null)
throw new NullReferenceException("Buffer can't be null!");
Int16 K = COSAC_KEY_SIZE / 16;
for (Int32 i = 0; i < rgb.Length; i++)
{
rgb[i] ^= (Byte)0xAB;
rgb[i] = (Byte)(rgb[i] >> 4 | rgb[i] << 4);
if (KeyValue != null)
{
rgb[i] ^= (Byte)(KeyValue[(Byte)(DecryptCounter & 0xFF) + 0]);
rgb[i] ^= (Byte)(KeyValue[(Byte)(DecryptCounter >> 8) + K]);
}
else if (IVValue != null)
{
rgb[i] ^= (Byte)(IVValue[(Byte)(DecryptCounter & 0xFF) + 0]);
rgb[i] ^= (Byte)(IVValue[(Byte)(DecryptCounter >> 8) + K]);
}
DecryptCounter++;
}
}
/// <summary>
/// Encrypts data with the COSAC algorithm.
/// </summary>
public void Encrypt(ref Byte[] rgb)
{
if (rgb == null)
throw new NullReferenceException("Buffer can't be null!");
Int16 K = COSAC_KEY_SIZE / 16;
for (Int32 i = 0; i < rgb.Length; i++)
{
rgb[i] ^= (Byte)0xAB;
rgb[i] = (Byte)(rgb[i] >> 4 | rgb[i] << 4);
if (IVValue != null)
{
rgb[i] ^= (Byte)(IVValue[(Byte)(EncryptCounter & 0xFF) + 0]);
rgb[i] ^= (Byte)(IVValue[(Byte)(EncryptCounter >> 8) + K]);
}
EncryptCounter++;
}
}
/// <summary>
/// Reset the decrypt and the encrypt counters.
/// </summary>
public void ResetCounter() { DecryptCounter = 0; EncryptCounter = 0; }
}
}






