Register for your free account! | Forgot your password?

You last visited: Today at 06:41

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



TQ Cipher Implementation (GoLang)

Discussion on TQ Cipher Implementation (GoLang) within the CO2 PServer Guides & Releases forum part of the CO2 Private Server category.

Reply
 
Old   #1
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
TQ Cipher Implementation (GoLang)

Introduction
I started refactoring my project to meet Go cipher interfaces and thought it would be interesting to share my new implementation of TQ's XOR cipher. I'm not entirely sure if my documentation/analysis is correct for TQ's cipher (primarily around it being a variant of RC4), but hopefully I can get some feedback on that and make some corrections if need be. Thanks, and happy holidays!

Implementation
Code:
// Package tq implements encryption using TQ Digital Entertainments in-house
// developed symmetric, counter-based XOR-cipher. Counters are separated by 
// encryption direction, thus two instances are required. 
//
// Copyright 2016-2017 Gareth Warry. All rights reserved.
// Use of this source code is governed by an MIT-style license that can be 
// found in the LICENSE file at the root of the project.
package tq

// BUG(agl): TQ's XOR Cipher is designed with multiple weaknesses. 
// Key scheduling uses no NP-hard calculations or random arguments. The 
// keystream is never modified after key scheduling, and encryption only relies
// on a counter as feedback. This cipher is a poor choice for new protocols.

import "strconv"

// A cipher is an instance of TQ's xor-cipher using a particular key.
type Cipher struct {
    key1 [0x100]byte
    key2 [0x100]byte
    x    uint16
}

// NewCipher creates and returns a new Cipher of TQ's XOR-cipher. The key
// argument should be the cipher's generator / seed of 8 bytes, static across 
// all client connections: { 0x9D, 0x0F, 0xFA, 0x13, 0x62, 0x79, 0x5C, 0x6D }.
// Two must be created to use as stream ciphers (decryption and encryption).
func NewCipher(key []byte) (*Cipher, error) {
    
    if len(key) == 8 {
        cipher := new(Cipher)
        for i := range cipher.key1 {
            cipher.key1[i] = key[0]
            cipher.key2[i] = key[4]
            key[0] = (key[1] + byte(key[0] * key[2])) * key[0] + key[3]
            key[4] = (key[5] - byte(key[4] * key[6])) * key[4] + key[7]
        }
        return cipher, nil
    } else { return nil, KeySizeError(len(key)) }
}

// KeySizeError is called when generating the Cipher's keystream using an 
// initial key of an invalid size (only supports 8 bytes in length).
type KeySizeError int
func (k KeySizeError) Error() string {
    return "security/tq: invalid key size " + strconv.Itoa(int(k))
}

// Copy replaces keystream and counter values of a child TQ Cipher instance
// with the values from this Cipher instance. Can be used after generating keys
// to create a second cipher stream (required for the opposite direction).
func (c *Cipher) Copy(child *Cipher) {
    
    copy(child.key1[:], c.key1[:])
    copy(child.key2[:], c.key2[:])
    child.x = c.x
}

// XORKeyStream sets dst with the result of XORing src with the key stream.
// Dst and src may be the same slice, but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
    
    for i, v := range src {
        dst[i] = v ^ 0xAB
        dst[i] = dst[i] >> 4 | dst[i] << 4
        dst[i] = dst[i] ^ c.key1[byte(c.x & 0xff)] 
        dst[i] = dst[i] ^ c.key2[byte(c.x >> 8)]
        c.x++
    }
}
Attached Files
File Type: txt LICENSE.txt (1.1 KB, 17 views)
Spirited is offline  
Old 12/23/2016, 16:59   #2


 
CptSky's Avatar
 
elite*gold: 0
Join Date: Jan 2008
Posts: 1,434
Received Thanks: 1,147
Quote:
Originally Posted by Spirited View Post
Introduction
I started refactoring my project to meet Go cipher interfaces and thought it would be interesting to share my new implementation of TQ's XOR cipher. I'm not entirely sure if my documentation/analysis is correct for TQ's cipher (primarily around it being a variant of RC4), but hopefully I can get some feedback on that and make some corrections if need be. Thanks, and happy holidays!
I don't think the TQ's XOR cipher should be considered asymmetric. The key used to encrypt/decrypt is the same which correspond to a symmetric algorithm. Counters do not make the cipher asymmetric, they are there to wrap over the key (e.g. make the cipher works like a stream cipher instead of reapplying the key over and over with the same index on random-size blocks and have patterns in the cipher text). Also it makes random decryption, in the middle of the connection, impossible if you haven't counted how many bytes were encrypted. Knowing that the counter is 16 bits, if you know the plaintext, kind of easy to guess and resync the counter

Also, as we already discussed in the past, I doubt it's based on RC4. I just think they both were designed in the same epoch, and as such present similar patterns for a symmetric stream cipher. The state of the TQ's XOR cipher is based on counters and the key never change while for RC4 it's the key scheduling algorithm that generate the initial state and then, the state will change with the feeded data. RC4 also has counters to wrap over the key, but that's logical for a stream cipher as we cannot have an infinite key to XOR with and that no cryptographic pseudo-random generator is used.
CptSky is offline  
Thanks
2 Users
Old 12/23/2016, 18:13   #3
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
Quote:
Originally Posted by CptSky View Post
I don't think the TQ's XOR cipher should be considered asymmetric. The key used to encrypt/decrypt is the same which correspond to a symmetric algorithm. Counters do not make the cipher asymmetric, they are there to wrap over the key (e.g. make the cipher works like a stream cipher instead of reapplying the key over and over with the same index on random-size blocks and have patterns in the cipher text). Also it makes random decryption, in the middle of the connection, impossible if you haven't counted how many bytes were encrypted. Knowing that the counter is 16 bits, if you know the plaintext, kind of easy to guess and resync the counter

Also, as we already discussed in the past, I doubt it's based on RC4. I just think they both were designed in the same epoch, and as such present similar patterns for a symmetric stream cipher. The state of the TQ's XOR cipher is based on counters and the key never change while for RC4 it's the key scheduling algorithm that generate the initial state and then, the state will change with the feeded data. RC4 also has counters to wrap over the key, but that's logical for a stream cipher as we cannot have an infinite key to XOR with and that no cryptographic pseudo-random generator is used.
Now that you mention it, I see how it's not too similar to RC4. The key sizes are roughly the same as RC4 at maximum key length and they both have similar XOR operations, but that's really it. Key scheduling is definitely very different, and TQ's cipher doesn't modify the keystream at any time. It's much weaker than RC4, considering patterns are exposed more easily since it's only using the counter as feedback. Am I right on that? I'll look more into the asymmetric / symmetric thing - as I'm not entirely sure how that applies to a CTR based keystream. Is the counter really just 16 bits?

Edit: So, more like this?
Code:
// Package tq implements encryption using TQ Digital Entertainments in-house
// developed symmetric, counter-based XOR-cipher. Counters are separated by 
// encryption direction, thus two instances are required. 
//
// Copyright 2016-2017 Gareth Warry. All rights reserved.
// Use of this source code is governed by an MIT-style license that can be 
// found in the LICENSE file at the root of the project.
package tq

// BUG(agl): TQ's XOR Cipher is designed with multiple weaknesses. 
// Key scheduling uses no NP-hard calculations or random arguments. The 
// keystream is never modified after key scheduling, and encryption only relies
// on a counter as feedback. This cipher is a poor choice for new protocols.

import "strconv"

// A cipher is an instance of TQ's xor-cipher using a particular key.
type Cipher struct {
    key1 [0x100]byte
    key2 [0x100]byte
    x    uint16
}

// NewCipher creates and returns a new Cipher of TQ's XOR-cipher. The key
// argument should be the cipher's generator / seed of 8 bytes, static across 
// all client connections: { 0x9D, 0x0F, 0xFA, 0x13, 0x62, 0x79, 0x5C, 0x6D }.
// Two must be created to use as stream ciphers (decryption and encryption).
func NewCipher(key []byte) (*Cipher, error) {
    
    if len(key) == 8 {
        cipher := new(Cipher)
        for i := range cipher.key1 {
            cipher.key1[i] = key[0]
            cipher.key2[i] = key[4]
            key[0] = (key[1] + byte(key[0] * key[2])) * key[0] + key[3]
            key[4] = (key[5] - byte(key[4] * key[6])) * key[4] + key[7]
        }
        return cipher, nil
    } else { return nil, KeySizeError(len(key)) }
}

// KeySizeError is called when generating the Cipher's keystream using an 
// initial key of an invalid size (only supports 8 bytes in length).
type KeySizeError int
func (k KeySizeError) Error() string {
    return "security/tq: invalid key size " + strconv.Itoa(int(k))
}

// Copy replaces keystream and counter values of a child TQ Cipher instance
// with the values from this Cipher instance. Can be used after generating keys
// to create a second cipher stream (required for the opposite direction).
func (c *Cipher) Copy(child *Cipher) {
    
    copy(child.key1[:], c.key1[:])
    copy(child.key2[:], c.key2[:])
    child.x = c.x
}

// XORKeyStream sets dst with the result of XORing src with the key stream.
// Dst and src may be the same slice, but otherwise should not overlap.
func (c *Cipher) XORKeyStream(dst, src []byte) {
    
    for i, v := range src {
        dst[i] = v ^ 0xAB
        dst[i] = dst[i] >> 4 | dst[i] << 4
        dst[i] = dst[i] ^ c.key1[byte(c.x & 0xff)] 
        dst[i] = dst[i] ^ c.key2[byte(c.x >> 8)]
        c.x++
    }
}
Spirited is offline  
Old 12/23/2016, 19:37   #4


 
CptSky's Avatar
 
elite*gold: 0
Join Date: Jan 2008
Posts: 1,434
Received Thanks: 1,147
Quote:
Originally Posted by Spirited View Post
Now that you mention it, I see how it's not too similar to RC4. The key sizes are roughly the same as RC4 at maximum key length and they both have similar XOR operations, but that's really it. Key scheduling is definitely very different, and TQ's cipher doesn't modify the keystream at any time. It's much weaker than RC4, considering patterns are exposed more easily since it's only using the counter as feedback. Am I right on that? I'll look more into the asymmetric / symmetric thing - as I'm not entirely sure how that applies to a CTR based keystream. Is the counter really just 16 bits?

Edit: So, more like this?
Asymmetry / symmetry is independent from the fact that the cipher is CTR based or not. AES is symmetric while it can be used in CTR mode. Idem for Blowfish, etc. RSA is an asymmetric cipher because you have a different key for encryption / decryption (one public, one private). Public-Private key based algorithms are asymmetric. Public key based algorithms are symmetric.

And yes, more like that.
CptSky is offline  
Thanks
1 User
Old 12/23/2016, 19:38   #5

 
Arby's Avatar
 
elite*gold: 83
Join Date: May 2011
Posts: 11,029
Received Thanks: 6,036
If you're here just to trash the thread, I'll delete the comments.
Arby is offline  
Thanks
1 User
Old 12/23/2016, 19:41   #6
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
Quote:
Originally Posted by CptSky View Post
Asymmetry / symmetry is independent from the fact that the cipher is CTR based or not. AES is symmetric while it can be used in CTR mode. Idem for Blowfish, etc. RSA is an asymmetric cipher because you have a different key for encryption / decryption (one public, one private). Public-Private key based algorithms are asymmetric. Public key based algorithms are symmetric.

And yes, more like that.
Ahh, okay. That makes much more sense. If there's nothing else immediately wrong, then I'll get to updating the main post when I get home in a few hours. Thanks JP!
Spirited is offline  
Old 12/23/2016, 21:12   #7
 
Super Aids's Avatar
 
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 946
Quote:
Originally Posted by Arby View Post
If you're here just to trash the thread, I'll delete the comments.
Okay let me just be constructive about why this code is ugly then.

I don't see why we can shit on Egy sources and other kind of crap code, but suddenly Mr. software engineer has protection from it.

Code:
package tq // Maybe a proper name? package tqcipher maybe?
import "strconv" // Jesus imports in strings?? is this 1977?

// Go attempts to be an easier C, but wtf??
type Cipher struct {
    key1 [0x100]byte
    key2 [0x100]byte
    x    uint64
}

// In C???
struct Cipher {
	char key1[0x100];
	char key2[0x100];
	uint64_t x;
};

// In worst case with typedef, seems like Go just borrowed this and put the identifier at top ??? ...
typedef struct {
	char key1[0x100];
	char key2[0x100];
	uint64_t x;
} Cipher;



// And this function syntax??? lol wot.
func NewCipher(key []byte) (*Cipher, error) {
    // Free space was inserted here.
    if len(key) == 8 { // Really here that there's no encapsulation of if statements.
        cipher := new(Cipher) // The := needs to die. It's so 1970 pascal. Oh wait forgot Google's modern is 70's...
        for i := range cipher.key1 { // yeah this syntax sucks too. Other language does this so much better eg, D: foreach (i; cipher.key1) { ... }
		
			// And this whole block... hate you don't end a statement with ; ...
            cipher.key1[i] = key[0]
            cipher.key2[i] = key[4]
            key[0] = (key[1] + byte(key[0] * key[2])) * key[0] + key[3]
            key[4] = (key[5] - byte(key[4] * key[6])) * key[4] + key[7]
        }
        return cipher, nil // Double return statements fuck yeah, because Go has a retarded error handling design.
    } else { return nil, KeySizeError(len(key)) }
}

// another ugly case of the go syndrome
type KeySizeError int
func (k KeySizeError) Error() string {
    return "security/tq: invalid key size " + strconv.Itoa(int(k)) // "strconv.Itoa(int(k))" lmfaoo???
}

// The rest is same Go garbage.
Super Aids is offline  
Old 12/23/2016, 22:16   #8
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
My threads are not complaint threads for the Go syntax and programming language. If you have actual feedback, thank you; else, find a hobby.
Spirited is offline  
Old 12/23/2016, 22:50   #9
 
Super Aids's Avatar
 
elite*gold: 0
Join Date: Dec 2012
Posts: 1,761
Received Thanks: 946
Well your code is written in Go, so my feedback is valid, since it still points to your code.
Super Aids is offline  
Old 12/24/2016, 02:36   #10
 
Spirited's Avatar
 
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
Quote:
Originally Posted by Super Aids View Post
Well your code is written in Go, so my feedback is valid, since it still points to your code.
That's really not the case, but keep your post. I'm not here to compete or argue.

@, Thanks again JP. It's nice to talk to someone else interested in cryptoanalysis.
Spirited is offline  
Reply


Similar Threads Similar Threads
C++ AES Implementation
12/19/2014 - Coding Snippets - 4 Replies
Hey, unter dem Projekt "FoxCrypt" möchte ich verschiedene Verschlüsselungs- und Hashalgorithmen als alleinstehende C++-Klassen implementieren und veröffentlichen. Den Anfang mache ich hier mit AES, zu dem ich leider keine wirklich alleinstehende Klasse für C++ finden konnte. Meine AES-Klasse implementiert lediglich blockweise-Verschlüsselung, die anderen Modes (CBC, CFB, CTR, OFB etc.) folgen später. Das ganze ist natürlich noch etwas optimierungswürdig und unterstützt z.B. noch kein...
sms billing implementation
01/22/2013 - SRO Private Server - 1 Replies
Hey guys im working with a new sro server and we have a moneybookers and paypal set up but i wanted to set up a Fortumo or something like tht for our pinoy players and the others who dnt use playpal. I have never set up sms b4 to work with my server so i would really appreciate help figuring this out. A link to a guide or something thatll get me thru this pain in the ass siutation. You can reply here or add me to Skype if you able to help....thanks
[HELP] Problems with new map implementation
09/09/2012 - Metin2 Private Server - 0 Replies
Hy, I'm having some problems in implementing new maps. Everything is done right but i can only warp to the new map with one character. Each time I try to warp with a different character I am warped to map1/village. And I get the following error in syserr: SYSERR: Sep 9 18:21:04 :: Entergame: !GetMovablePosition (name TestWarp 1243200x1243300 map 195 changed to 1273200x1274000) I don't think that it is an implementation error because there is 1 character i can warp there. But I made 10...
[Java] Conquer blowfish cipher implementation
04/26/2011 - CO2 Programming - 5 Replies
Since tomas has been putting so much effort into building his proxy, I'll put up my codes for blowfish cipher so that I can help ttomas and any other java developers out there. The main class that you will need is the BlowFishCryptor. It's a easy to use wrapper that I wrote for the other 2 blowfish classes. The other 2 files are directly translated from openssl library, and i think it is done by some guru from this forum; sparkie knows who that person is; i do not think he will mind me...



All times are GMT +2. The time now is 06:41.


Powered by vBulletin®
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2024 elitepvpers All Rights Reserved.