#!/usr/bin/env python
#
# XOR, ROL, ROT permuter
# Doing the same permutes as http://blog.didierstevens.com/programs/xorsearch/
# but printing all output through a strings filter, allowing for use of 
# command-line tools to be applied to extend the search (e.g. Gnu GREP)
# It also performs a double XOR (2 bytes).
#
# Author : geir@underworld.no (c) 2012,2013
#
# Usage: 
# $> cat FILETOSEARCH | ./xorrolrot.py | grep -i http
#
# Copyright (c) 2012,2013 Geir Skjotskift
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met: 
#
# 1. Redistributions of source code must retain the above copyright notice, this
#    list of conditions and the following disclaimer. 
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution. 
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# 'ivur;-.rnenqukbi/ldv.|fghp'

import sys, re

ROL_MIN = 1
ROL_MAX = 26
ROT_MIN = 1
ROT_MAX = 26
XOR_MIN = 0
XOR_MAX = 256

def strings(data):
    return list(set(re.findall("[\040-\176\s]{4,}", data)))


def xor_string(s, v):
    return "".join([chr(ord(c)^v) for c in s])
    

def double_xor_string(s, v1, v2):
    return "".join([chr(ord(c)^(v1,v2)[i % 2]) for i, c in enumerate(s)])


def rol_string(s, v):
    return "".join([chr((ord(c)-v) % 256) for c in s])


def rot_string(s, v):
    return "".join([chr((ord(c)+v) % 256) for c in s])


def find_all(d):
    res = []
    for x in range(XOR_MIN, XOR_MAX):
        if x == 0 or x == 0x20:
            continue
        for s in strings(xor_string(d, x)):
            res.append("XOR     \"0x%x\": %s" % (x, s))
	for y in range(XOR_MIN, XOR_MAX):
            if y == 0 or y == 0x20 or x == y:
                continue
            for s in strings(double_xor_string(d, x, y)):
                res.append("XOR \"0x%x 0x%x\": %s"  % (x, y, s))
    for x in range(ROL_MIN, ROL_MAX):
        for s in strings(rol_string(d, x)):
            res.append("ROL     \"0x%x\": %s" % (x, s))
    for x in range(ROT_MIN, ROT_MAX):
        for s in strings(rot_string(d, x)):
            res.append("ROT     \"0x%x\": %s" % (x, s))
    return reversed(sorted(res, key=len))

if __name__ == '__main__':

    data = sys.stdin.read()
    print "\n".join(find_all(data))
