Code:
// *
// * ******** COPS v6 Emulator - Open Source ********
// * Copyright (C) 2011 - 2014 Jean-Philippe Boivin
// *
// * Please read the WARNING, DISCLAIMER and PATENTS
// * sections in the LICENSE file.
// *
using System;
namespace COServer.Security.Cryptography
{
/// <summary>
/// TQ Digital's Asymmetric Cipher (used on the servers).
/// </summary>
public class TqCipher
{
/// <summary>
/// Integer constant used to generate the initialization vector.
/// </summary>
public static UInt32 P = 0x13FA0F9D;
/// <summary>
/// Integer constant used to generate the initialization vector.
/// </summary>
public static UInt32 G = 0x6D5C7962;
/// <summary>
/// The key size in bytes.
/// </summary>
private const int KEY_SIZE = 512;
/// <summary>
/// The initial key.
/// </summary>
private readonly Byte[] mIV = new Byte[KEY_SIZE];
/// <summary>
/// The alternate key (to be used for decryption).
/// </summary>
private readonly Byte[] mAltKey = new Byte[KEY_SIZE];
/// <summary>
/// Whether or not the alternate key is used for decryption.
/// </summary>
private bool mUsingAltKey = false;
/// <summary>
/// The encryption counter.
/// </summary>
private UInt16 mEnCounter = 0;
/// <summary>
/// The decryption counter.
/// </summary>
private UInt16 mDeCounter = 0;
/// <summary>
/// Create a new cipher instance. The key will be generated
/// using the P and G constants.
/// </summary>
public unsafe TqCipher()
{
const int K = KEY_SIZE / 2;
fixed (UInt32* _p = &P, _g = &G)
{
Byte* p = (Byte*)_p;
Byte* g = (Byte*)_g;
for (int i = 0; i < K; ++i)
{
mIV[i + 0] = p[0];
mIV[i + K] = g[0];
p[0] = (Byte)((p[1] + (Byte)(p[0] * p[2])) * p[0] + p[3]);
g[0] = (Byte)((g[1] - (Byte)(g[0] * g[2])) * g[0] + g[3]);
}
}
}
/// <summary>
/// Generates an alternate key to use for the algorithm and reset
/// the encryption counter.
///
/// In Conquer Online: A = Token, B = AccountUID
/// </summary>
public unsafe void GenerateAltKey(Int32 A, Int32 B)
{
const int K = KEY_SIZE / 2;
UInt32 tmp1 = (UInt32)(((A + B) ^ 0x4321) ^ A);
UInt32 tmp2 = tmp1 * tmp1;
Byte* tmpKey1 = (Byte*)&tmp1;
Byte* tmpKey2 = (Byte*)&tmp2;
for (int i = 0; i < K; ++i)
{
mAltKey[i + 0] = (Byte)(mIV[i + 0] ^ tmpKey1[(i % 4)]);
mAltKey[i + K] = (Byte)(mIV[i + K] ^ tmpKey2[(i % 4)]);
}
mUsingAltKey = true;
mEnCounter = 0;
}
/// <summary>
/// Encrypts data with the algorithm.
/// </summary>
public void Encrypt(ref Byte[] aBuf, int aLength)
{
const int K = KEY_SIZE / 2;
for (int i = 0; i < aLength; ++i)
{
aBuf[i] ^= (Byte)0xAB;
aBuf[i] = (Byte)(aBuf[i] >> 4 | aBuf[i] << 4);
aBuf[i] ^= (Byte)(mIV[(Byte)(mEnCounter & 0xFF) + 0]);
aBuf[i] ^= (Byte)(mIV[(Byte)(mEnCounter >> 8) + K]);
++mEnCounter;
}
}
/// <summary>
/// Decrypts data with the algorithm.
/// </summary>
public void Decrypt(ref Byte[] aBuf, int aLength)
{
const int K = KEY_SIZE / 2;
Byte[] key = mUsingAltKey ? mAltKey : mIV;
for (int i = 0; i < aLength; ++i)
{
aBuf[i] ^= (Byte)0xAB;
aBuf[i] = (Byte)(aBuf[i] >> 4 | aBuf[i] << 4);
aBuf[i] ^= (Byte)(key[(Byte)(mDeCounter & 0xFF) + 0]);
aBuf[i] ^= (Byte)(key[(Byte)(mDeCounter >> 8) + K]);
++mDeCounter;
}
}
/// <summary>
/// Resets the decrypt and the encrypt counters.
/// </summary>
public void ResetCounters() { mDeCounter = 0; mEnCounter = 0; }
}
}
Code:
// * ************************************************************
// * * START: cocac.cs *
// * ************************************************************
// * ************************************************************
// * INFORMATIONS
// * ************************************************************
// * Conquer Online Client Asymmetric Cipher for the library.
// * cocac.cs
// *
// * --
// *
// * Feel free to use this class in your projects, but don't
// * remove the header to keep the paternity of the class.
// *
// * ************************************************************
// * CREDITS
// * ************************************************************
// * Originally created by CptSky (October 25th, 2011)
// * Copyright (C) 2011 CptSky
// *
// * ************************************************************
// * SPECIAL THANKS
// * ************************************************************
// * Sparkie (unknownone @ e*pvp)
// *
// * ************************************************************
using System;
namespace CO2_CORE_DLL.Security.Cryptography
{
/// <summary>
/// Conquer Online Client Asymmetric Cipher
/// </summary>
public unsafe class COCAC
{
private const Int32 COCAC_IV = 512;
private const Int32 COCAC_KEY = 512;
private Byte* BufIV = null;
private Byte* BufKey = null;
private UInt16 EncryptCounter = 0;
private UInt16 DecryptCounter = 0;
/// <summary>
/// Create a new COCAC instance.
/// </summary>
public COCAC() { }
~COCAC()
{
if (BufIV != null)
Kernel.free(BufIV);
if (BufKey != null)
Kernel.free(BufKey);
}
/// <summary>
/// Generates an initialization vector (IV) to use for the algorithm.
/// CO2(P: 0x13FA0F9D, G: 0x6D5C7962)
/// </summary>
public void GenerateIV(Int32 P, Int32 G)
{
if (BufIV != null)
Kernel.free(BufIV);
BufIV = (Byte*)Kernel.malloc(COCAC_IV);
Int16 K = COCAC_IV / 2;
Byte* pBufPKey = (Byte*)&P;
Byte* pBufGKey = (Byte*)&G;
for (Int16 i = 0; i < K; i++)
{
BufIV[i + 0] = pBufPKey[0];
BufIV[i + K] = pBufGKey[0];
pBufPKey[0] = (Byte)((pBufPKey[1] + (Byte)(pBufPKey[0] * pBufPKey[2])) * pBufPKey[0] + pBufPKey[3]);
pBufGKey[0] = (Byte)((pBufGKey[1] - (Byte)(pBufGKey[0] * pBufGKey[2])) * pBufGKey[0] + pBufGKey[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)
{
Kernel.assert(BufIV != null);
if (BufKey != null)
Kernel.free(BufKey);
BufKey = (Byte*)Kernel.malloc(COCAC_KEY);
Int16 K = COCAC_KEY / 2;
UInt32 tmp1 = 0;
tmp1 = (UInt32)(A + B);
Byte* tmpKey1 = (Byte*)&tmp1;
((Int16*)tmpKey1)[0] ^= 0x4321;
for (SByte i = 0; i < 4; i++)
tmpKey1[3 - i] ^= (Byte)(A >> (24 - (8 * i)));
UInt32 tmp2 = tmp1;
tmp2 *= tmp2;
Byte* tmpKey2 = (Byte*)&tmp2;
for (Int16 i = 0; i < K; i++)
{
BufKey[i + 0] = (Byte)(BufIV[i + 0] ^ tmpKey1[(i % 4)]);
BufKey[i + K] = (Byte)(BufIV[i + K] ^ tmpKey2[(i % 4)]);
}
DecryptCounter = 0;
}
/// <summary>
/// Encrypts data with the COCAC algorithm.
/// </summary>
public void Encrypt(Byte* pBuf, Int32 Length)
{
Kernel.assert(pBuf != null);
Kernel.assert(Length > 0);
Int16 K = COCAC_IV / 2;
for (Int32 i = 0; i < Length; i++)
{
if (BufKey != null)
{
pBuf[i] ^= (Byte)(BufKey[(Byte)(DecryptCounter >> 8) + K]);
pBuf[i] ^= (Byte)(BufKey[(Byte)(DecryptCounter & 0xFF) + 0]);
}
else if (BufIV != null)
{
pBuf[i] ^= (Byte)(BufIV[(Byte)(EncryptCounter >> 8) + K]);
pBuf[i] ^= (Byte)(BufIV[(Byte)(EncryptCounter & 0xFF) + 0]);
}
pBuf[i] = (Byte)(pBuf[i] >> 4 | pBuf[i] << 4);
pBuf[i] ^= (Byte)0xAB;
EncryptCounter++;
}
}
/// <summary>
/// Decrypts data with the COCAC algorithm.
/// </summary>
public void Decrypt(Byte* pBuf, Int32 Length)
{
Kernel.assert(pBuf != null);
Kernel.assert(Length > 0);
Int16 K = COCAC_IV / 2;
if (BufKey != null)
K = COCAC_KEY / 2;
for (Int32 i = 0; i < Length; i++)
{
if (BufIV != null)
{
pBuf[i] ^= (Byte)(BufIV[(Byte)(EncryptCounter >> 8) + K]);
pBuf[i] ^= (Byte)(BufIV[(Byte)(EncryptCounter & 0xFF) + 0]);
}
pBuf[i] = (Byte)(pBuf[i] >> 4 | pBuf[i] << 4);
pBuf[i] ^= (Byte)0xAB;
DecryptCounter++;
}
}
/// <summary>
/// Encrypts data with the COCAC algorithm.
/// </summary>
public void Encrypt(ref Byte[] Buf)
{
Kernel.assert(Buf != null);
Kernel.assert(Buf.Length > 0);
Int32 Length = Buf.Length;
fixed (Byte* pBuf = Buf)
Encrypt(pBuf, Length);
}
/// <summary>
/// Decrypts data with the COCAC algorithm.
/// </summary>
public void Decrypt(ref Byte[] Buf)
{
Kernel.assert(Buf != null);
Kernel.assert(Buf.Length > 0);
Int32 Length = Buf.Length;
fixed (Byte* pBuf = Buf)
Decrypt(pBuf, Length);
}
/// <summary>
/// Resets the decrypt and the encrypt counters.
/// </summary>
public void ResetCounters() { DecryptCounter = 0; EncryptCounter = 0; }
}
}
// * ************************************************************
// * * END: cocac.cs *
// * ************************************************************
I tried to decrypt it using both methods without success.






