Remove all the files except README

This commit is contained in:
Amanpreet Singh 2015-04-26 10:49:19 +05:30
parent e72ba89197
commit 621fb77b02
16 changed files with 0 additions and 893 deletions

Binary file not shown.

Binary file not shown.

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 hellman ( hellman1908@gmail.com )
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.

View file

@ -1,109 +0,0 @@
xortool.py
====================
A tool to do some xor analysis:
- guess the key length (based on count of equal chars)
- guess the key (base on knowledge of most frequent char)
Usage
---------------------
! *python3 is not supported, use python 2.x*
```
xortool [-h|--help] [OPTIONS] [<filename>]
Options:
-l,--key-length length of the key (integer)
-c,--char most possible char (one char or hex code)
-m,--max-keylen=32 maximum key length to probe (integer)
-x,--hex input is hex-encoded str
-b,--brute-chars brute-force all possible characters
-o,--brute-printable same as -b but will only use printable
characters for keys
```
Example
---------------------
```bash
# xor is xortool/xortool-xor
tests $ xor -f /bin/ls -s "secret_key" > binary_xored
tests $ xortool binary_xored
The most probable key lengths:
2: 5.0%
5: 8.7%
8: 4.9%
10: 15.4%
12: 4.8%
15: 8.5%
18: 4.8%
20: 15.1%
25: 8.4%
30: 14.9%
Key-length can be 5*n
Most possible char is needed to guess the key!
# 00 is the most frequent byte in binaries
tests $ xortool binary_xored -l 10 -c 00
...
1 possible key(s) of length 10:
secret_key
# decrypted ciphertexts are placed in ./xortool_out/Number_<key repr>
# ( have no better idea )
tests $ md5sum xortool_out/0_secret_key /bin/ls
29942e290876703169e1b614d0b4340a xortool_out/0_secret_key
29942e290876703169e1b614d0b4340a /bin/ls
```
The most common use is to pass just the encrypted file and the most frequent character (usually 00 for binaries and 20 for text files) - length will be automatically chosen:
```bash
tests $ xortool tool_xored -c 20
The most probable key lengths:
2: 5.6%
5: 7.8%
8: 6.0%
10: 11.7%
12: 5.6%
15: 7.6%
20: 19.8%
25: 7.8%
28: 5.7%
30: 11.4%
Key-length can be 5*n
1 possible key(s) of length 20:
an0ther s3cret \xdd key
```
Here, the key is longer then default 32 limit:
```bash
tests $ xortool ls_xored -c 00 -m 64
The most probable key lengths:
3: 3.3%
6: 3.3%
9: 3.3%
11: 7.0%
22: 6.9%
24: 3.3%
27: 3.2%
33: 18.4%
44: 6.8%
55: 6.7%
Key-length can be 3*n
1 possible key(s) of length 33:
really long s3cr3t k3y... PADDING
```
So, if automated decryption fails, you can calibrate:
- (`-m`) max length to try longer keys
- (`-l`) selected length to see some interesting keys
- (`-c`) the most frequent char to produce right plaintext
Author: hellman ( hellman1908@gmail.com )
License: MIT License (opensource.org/licenses/MIT)

View file

@ -1,35 +0,0 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from distutils.core import setup
import xortool
setup(name='xortool',
version=xortool.__version__,
author='hellman',
author_email='hellman1908@gmail.com',
license="MIT",
url='https://github.com/hellman/xortool',
description='Tool for xor cipher analysis',
long_description=open("README.md").read(), # not in rst, but something
keywords="xor xortool analysis",
packages=['xortool'],
provides=['xortool'],
install_requires=['docopt>=0.6.1'],
scripts=["xortool/xortool", "xortool/xortool-xor"],
classifiers=['Development Status :: 4 - Beta',
'Intended Audience :: Science/Research',
'Intended Audience :: Information Technology',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2',
'License :: OSI Approved :: MIT License',
'Topic :: Scientific/Engineering :: Mathematics',
'Topic :: Security :: Cryptography',
],
)

Binary file not shown.

Binary file not shown.

View file

@ -1 +0,0 @@
ラ込マ<EFBFBD>瞹悴采<EFBFBD>ニミ€ゥテ檮ォハヘマ<EFBFBD>ロ擡フラ<EFBFBD>ヤ棘サ゚ヌマキテン€ウンメ巻ネ怜ラ込マ<EFBFBD>€<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>灘ヤ<EFBFBD>€ヘ崛タホユ<EFBFBD>糟゚郞奈蕫鈷<EFBFBD>怕ユ巐<EFBFBD><EFBFBD>レ攴ンホ堪洞蜉ナラ<EFBFBD>ヒムΥツノ<EFBFBD>ハ档ギハマスツミ崛トミ<EFBFBD>ルヨ€ュネ檮ォハヘマゥナラ幻桜ネウ罪仭゚ロマアヒ積<EFBFBD><EFBFBD>メ漢゙ロ蟲フユ<EFBFBD>゙ヒ攴彩<EFBFBD>ル檮ォハヘマァツヒマャネホ€ャル梹ャネ栫アル档ギハ桓斎堪ネ積<EFBFBD>蒭マァツヒマスフミマクトニマアテロ螻ヒ椦カネヘ<EFBFBD>マヒ渥ぴ<EFBFBD>トハ蒔トム<EFBFBD>桜ネイチ梃サ゚ハ執テメ<EFBFBD>マロマケチ゚<EFBFBD>ルムマャネン換ロロマソ歳蒔ホヨチヤァ<EFBFBD><EFBFBD>ルヨ堪栽€ォ゚ン<EFBFBD>ツリマキテリ€ャタ゚峭ツミマソマム坎剤垰゙梟ュ彩<EFBFBD>歳擲マメ患載蒔フ檮ゾロマアヒ椦カネエィ煽棔ャツヤ歓ル積<EFBFBD><EFBFBD>堪ネ梟ュ罪<EFBFBD>ネ゚悸彩€<EFBFBD>リヘ<EFBFBD>楨ク<EFBFBD>トミ崕゚リ漆ネ梹ィフラαマメ<EFBFBD>フハ袂込マ<EFBFBD>込マカルハ滉愕リフ現レ゚攴τ攣ま垰ララΥフ大ヤ苙亞リメ<EFBFBD>フホ洳ネン<EFBFBD>ルロマキル棘サ゚ヌマウリン<EFBFBD>トリマァツヒマスツヒ<EFBFBD>妻堪トリ<EFBFBD>ルヨ<EFBFBD>ンフ€シチロ<EFBFBD>レ゚慟テム<EFBFBD>゚ロ浤゚ハ桓剤敢ツフ<EFBFBD>マヌマイツム┨テルマェナフ€ォハヨマェナロマコフハ湿フヘ嬉刷敢ツフ<EFBFBD>゚ロ浤゚ハ<EFBFBD>ハエ<EFBFBD>マヒ<EFBFBD>ンメ漢゙ロマスナロ厳彩<EFBFBD>鮭ョ渚ヘ<EFBFBD>ホロマキル梛ギン坏゙ロ<EFBFBD>フメ愕罪マイツハマアヒエ洳ツワ<EFBFBD>タ゚峭ホ棡キルヒ蒔トム<EFBFBD>Χ袂モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ態ァ孖ィネフ<EFBFBD><EFBFBD><EFBFBD>槐ロハ€<EFBFBD><EFBFBD><EFBFBD>エ蜈鵠ナロ椪イツヘ<EFBFBD>ハ棡カフフ桓采唆ネン岶細<EFBFBD>゙ハ蒔トン軸チヌマイトミ┰ノ檮キテ゚攅ネヘマウツヘ<EFBFBD>ツリマェナロ<EFBFBD>込マ<EFBFBD>込峭タロ<EFBFBD>チロ室゙椦ア在攸゙ヨ姦載址トミ<EFBFBD>ルヨ<EFBFBD>ノメ€ョネミヌ<EFBFBD>槃摸フ<EFBFBD>ルムマクトニチヤァ袞<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ホム興細<EFBFBD>テム<EFBFBD>寢マシトハマスチロ鴫<EFBFBD>マ看ラ<EFBFBD>トヘマケネハ峭テルマュチム亟ヤ梔キユロ欽込マ<EFBFBD>込マシリハマサユホ歓ル梟ーホムぐフハ<EFBFBD>チロマスナ゚∋ネヘマアテ樂鼾ワ<EFBFBD>αルリ€ャタヘマイトユ<EFBFBD><EFBFBD>涕フ仙ヤ<EFBFBD><EFBFBD>槃看ロマョ゚ロ弦゙ラ€ー采<EFBFBD>ルヨ<EFBFBD>ヘヘ<EFBFBD>ナメネ<EFBFBD>フミ虞ツフマセフヘ<EFBFBD>ナメネ<EFBFBD>ヒヒ⊃ルラ€ー載€<EFBFBD>テム<EFBFBD>゙ロ患ァ槃<EFBFBD>込マ<EFBFBD>ルムマシネ椦カネ檮ザハチヤァ袞<EFBFBD><EFBFBD><EFBFBD>簟マ墜ミ圜◇峺ネフ<EFBFBD>゙ヨ€ォチレマシネ梹<EFBFBD>レ゚<EFBFBD>ルムマョ゚ロ匳テハマコネリ<EFBFBD>トミ<EFBFBD>ルヨ<EFBFBD>゙ヌぞツメ<EFBFBD>込マ<EFBFBD>込。<EFBFBD><EFBFBD><EFBFBD>發滸梟ー彩<EFBFBD><EFBFBD>テヒ列チラすルヘチカ到<EFBFBD>フレ堪菜<EFBFBD>ネ積<EFBFBD>菻マケチラ鎖細嶽込マ<EFBFBD>込マギ梛サヒラ⊇ノ梟ー高浤゙ラ暦<EFBFBD><EFBFBD>ωム<EFBFBD>レヨ<EFBFBD>ナ桙ォ゙ハマーツハマウフユ<EFBFBD>ルヨ<EFBFBD>ツハ<EFBFBD>゚エマ<EFBFBD>込マ<EFBFBD>栽無マムΟ<EFBFBD><EFBFBD>リニタイトモ<EFBFBD>゙睡熏゚卅トメ湿チロチヤ込マ<EFBFBD>込マ<EFBFBD><EFBFBD>イトワ佼怺゚Ιエエ<EFBFBD>鵠イ<EFBFBD><EFBFBD><EFBFBD>タ宕サネロマセパさフ厮クリミ謙トム<EFBFBD>ハラ匳゙椈ャツミ<EFBFBD>゚ロ忰チハ<EFBFBD><EFBFBD><EFBFBD>チロ鹿ル梔ア゚エマ<EFBFBD>込マ<EFBFBD>酷゚<EFBFBD>涼ヤァ袞<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>チラ叉€ラ棺ネ桴ュポ<EFBFBD>萱沖テン峭ツミマケトネ姦宰擲テルマャネヘ坿ルヘマクツフ<EFBFBD>込マ<EFBFBD><EFBFBD>テ宕ールロ握フメマュネン€ーノ棔ソ゚゚そルロ擯Χ蜈込ナロ楙サロロ攸チ槁ウツヘ帋<EFBFBD>験チメ蒔トム<EFBFBD>゙ホ歓トリ<EFBFBD>フハ<EFBFBD>テヘマソ゚ロマシ゚ム┰テ積<EFBFBD><EFBFBD><EFBFBD>ホム興宰<EFBFBD>ホヨ<EFBFBD>込マ<EFBFBD><EFBFBD>在址゚ロ↑チヌマェナロ攴細<EFBFBD>トミマウツヘ<EFBFBD>ポ惱゙梟ーナロ攅ルロ<EFBFBD>ヒフ€ウ彩<EFBFBD>采攅ハラ<EFBFBD>フメ<EFBFBD>込マ<EFBFBD>込辞ルヨ€ャ獄<EFBFBD>在鹿ネ椦カネフ<EFBFBD>トヘマソ柵ャ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>゙ホ歓トリ<EFBFBD>フハ<EFBFBD>テ梟ー彩<EFBFBD>€スフメ間込マ<EFBFBD>込マクトメ机采<EFBFBD>トヘマコネリ<EFBFBD>ネレマォ゙ラ∋彩<EFBFBD>載敢フヒΜ<EFBFBD>細愕怺ル<EFBFBD><EFBFBD><EFBFBD>トミ鹸リレ桓ю袂込マ<EFBFBD>込マ療梹ーヤ梃ゾロマゥネ梹ャネ桙ギヘ<EFBFBD>ハ梟ーヒム攀フハ<EFBFBD>テ椦ア在€ャ゚ロ謙彩<EFBFBD>栽渊ホラ温ポ峭ツミチヤ込マ<EFBFBD>込マ陵椁アリ梔キテレマェナロマュンロ弦ヒラ諺ルラ€ー菜€ャ塞€ォ゚档ソテル堊ハロマシネ梔ソリメ岌歳<EFBFBD>フヘ間込マ<EFBFBD>込マュネミ<EFBFBD>フ椌サンム擡宰<EFBFBD>ナ梟ー゙ハ抬ホハ<EFBFBD>テ梳ー宰<EFBFBD>ル椦ア菜<EFBFBD><EFBFBD><EFBFBD>ヒマコツミネェ斎耳ネ椦アァ槃<EFBFBD>込マ<EFBFBD>ヒラ<EFBFBD>ルヨ<EFBFBD>゙ホ歓トリ<EFBFBD>フハ<EFBFBD>テ椁アリフ惱チリチヤァ槃<EFBFBD>込マ<EFBFBD><EFBFBD><EFBFBD>レ゚<EFBFBD>トハマクトミ軸チヌマュナム坿ノ档アツユマイトユ<EFBFBD><EFBFBD><EFBFBD>ルヨ<EFBFBD>ハロ⊇゚ラ<EFBFBD>゙ホ歓トリ<EFBFBD>フハ<EFBFBD>テエマ<EFBFBD>込マ<EFBFBD><EFBFBD>テム<EFBFBD>ホム擣ネン庠在鴫剤<EFBFBD>゙ロ寛細<EFBFBD>ルヨ<EFBFBD>゙ネー崎梔キチロチ<EFBFBD>搾垤ルロマソ菜勧在<EFBFBD>テル姦ァ槃<EFBFBD>込マ<EFBFBD>ツミマェツホマアヒ椦カネ梭サテロ攅ホ棡ョネン<EFBFBD>トン蒔トム<EFBFBD>ポ<EFBFBD>マロマウフレ<EFBFBD>レラ峺ツヒ<EFBFBD>ノヒ浚トン蒔トム<EFBFBD>込マ<EFBFBD>込マアヒ椦カネ椈カツメ<EFBFBD><EFBFBD>ー昶<EFBFBD>漱鋧コネヘ軒トホ峭ツミチヤァ袞<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ムそ采<EFBFBD>ルヨ<EFBFBD>ヒヒ⊃ルラ€ー゙椈カトン<EFBFBD>フメ愕斎鴫ノメ桓桜ソィ屓汐ネ梃ォ゚フ寛ルメ<EFBFBD>マフ€オネミチヤ込マ<EFBFBD>込マ<EFBFBD>ネル<EFBFBD>フミ<EFBFBD>蒡呟犀€アニヒ洒采舷フヘ<EFBFBD>テ゚Υヤ梏ソンホ寛宰<EFBFBD>テ栫アル栫サネレ桓<EFBFBD>マ看ラ慟込マ<EFBFBD>込マカフホ渊テヘマキテ梭サル゚脅゚ラ∈ツ免<EFBFBD>フミ<EFBFBD>ハロ峅フモ換テリ€<EFBFBD><EFBFBD>蒡呟斎鴫ノメ<EFBFBD>ハ梳クァ槃<EFBFBD>込マ<EFBFBD>ルヨ姦ネ梔ォテン峭ツミ<EFBFBD>トヘマ第椦カツヒ宛罪⊆彩<EFBFBD>゚ロマソ゚ロマョフハ幻ネヘマソロ゚<EFBFBD>フワ<EFBFBD>€<EFBFBD>ヒラ琳込マ<EFBFBD>込マェナロマ<EFBFBD>ネル<EFBFBD>ホム興罪<EFBFBD>レロΥΧ蝣モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蔵モタ蜍チフ<EFBFBD>ナ椨ャネホ渊゚エ峡ネホ渊゚<EFBFBD>攴ノヨ蒔<EFBFBD>€ウァ

Binary file not shown.

View file

@ -1,5 +0,0 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-
__all__ = ["args", "colors", "libcolors", "routine"]
__version__ = "0.96"

View file

@ -1,28 +0,0 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from docopt import docopt
from routine import parse_char
class ArgError(Exception):
pass
def parse_parameters(doc, version):
p = docopt(doc, version=version)
p = {k.lstrip("-"): v for k, v in p.items()}
try:
return {
"input_is_hex": bool(p["hex"]),
"max_key_length": int(p["max-keylen"]),
"known_key_length": int(p["key-length"]) if p["key-length"] else None,
"most_frequent_char": parse_char(p["char"]) if p["char"] else None,
"brute_chars": bool(p["brute-chars"]),
"brute_printable": bool(p["brute-printable"]),
"frequency_spread": 0, # to be removed
"filename": p["FILE"] if p["FILE"] else "-", # stdin by default
}
except ValueError as err:
raise ArgError(str(err))

View file

@ -1,19 +0,0 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from libcolors import color
C_RESET = color()
C_FATAL = color("red")
C_WARN = color("yellow")
C_KEYLEN = color("green")
C_PROB = color("white", attrs="")
C_BEST_KEYLEN = color("green", attrs="bold")
C_BEST_PROB = color("white", attrs="bold")
C_DIV = color(attrs="bold")
C_KEY = color("red", attrs="bold")
C_BOLD = color(attrs="bold")
C_COUNT = color("yellow", attrs="bold")

View file

@ -1,80 +0,0 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os
BASH_ATTRIBUTES = {"regular": "0",
"bold": "1", "underline": "4", "strike": "9",
"light": "1", "dark": "2",
"invert": "7"} # invert bg and fg
BASH_COLORS = {"black": "30", "red": "31", "green": "32", "yellow": "33",
"blue": "34", "purple": "35", "cyan": "36", "white": "37"}
BASH_BGCOLORS = {"black": "40", "red": "41", "green": "42", "yellow": "43",
"blue": "44", "purple": "45", "cyan": "46", "white": "47"}
def _main():
header = color("white", "black", "dark")
print
print header + " " + "Colors and backgrounds: " + color()
for c in _keys_sorted_by_values(BASH_COLORS):
c1 = color(c)
c2 = color("white" if c != "white" else "black", bgcolor=c)
print (c.ljust(10) +
c1 + "colored text" + color() + " " +
c2 + "background" + color())
print
print header + " " + "Attributes: " + color()
for c in _keys_sorted_by_values(BASH_ATTRIBUTES):
c1 = color("red", attrs=c)
c2 = color("white", attrs=c)
print (c.ljust(13) +
c1 + "red text" + color() + " " +
c2 + "white text" + color())
print
return
def color(color=None, bgcolor=None, attrs=None):
if not is_bash():
return ""
ret = "\x1b[0"
if attrs:
for attr in attrs.lower().split():
attr = attr.strip(",+|")
if attr not in BASH_ATTRIBUTES:
raise ValueError("Unknown color attribute: " + attr)
ret += ";" + BASH_ATTRIBUTES[attr]
if color:
if color in BASH_COLORS:
ret += ";" + BASH_COLORS[color]
else:
raise ValueError("Unknown color: " + color)
if bgcolor:
if bgcolor in BASH_BGCOLORS:
ret += ";" + BASH_BGCOLORS[bgcolor]
else:
raise ValueError("Unknown background color: " + bgcolor)
return ret + "m"
def is_bash():
return os.environ.get("SHELL", "unknown").endswith("bash")
def _keys_sorted_by_values(adict):
"""Return list of the keys of @adict sorted by values."""
return sorted(adict, key=adict.get)
if __name__ == "__main__":
_main()

View file

@ -1,98 +0,0 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os
import sys
import string
class MkdirError(Exception):
pass
def load_file(filename):
if filename == "-":
return sys.stdin.read()
fd = open(filename, "rb")
contents = fd.read()
fd.close()
return contents
def save_file(filename, data):
fd = open(filename, "wb")
fd.write(data)
fd.close()
return
def mkdir(dirname):
if os.path.exists(dirname):
return
try:
os.mkdir(dirname)
except BaseException as err:
raise MkdirError(str(err))
return
def rmdir(dirname):
if dirname[-1] == os.sep:
dirname = dirname[:-1]
if os.path.islink(dirname):
return # do not clear link - we can get out of dir
files = os.listdir(dirname)
for f in files:
if f == '.' or f == '..':
continue
path = dirname + os.sep + f
if os.path.isdir(path):
rmdir(path)
else:
os.unlink(path)
os.rmdir(dirname)
return
def decode_from_hex(text):
only_hex_digits = "".join([c for c in text if c in string.hexdigits])
return only_hex_digits.decode("hex")
def parse_char(ch):
"""
'A' or '\x41' or '41'
"""
if len(ch) == 1:
return ord(ch)
if ch[0:2] == "\\x":
ch = ch[2:]
if not ch:
raise ValueError("Empty char")
return ord(chr(int(ch, 16)))
def dexor(text, key):
ret = list(text)
mod = len(key)
for index, char in enumerate(ret):
ret[index] = chr(ord(char) ^ ord(key[index % mod]))
return "".join(ret)
def die(exitMessage, exitCode=1):
print exitMessage
sys.exit(exitCode)
def is_linux():
return sys.platform.startswith("linux")
def alphanum(s):
lst = list(s)
for index, char in enumerate(lst):
if char in (string.letters + string.digits):
continue
lst[index] = char.encode("hex")
return "".join(lst)

View file

@ -1,381 +0,0 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-
"""
xortool
A tool to do some xor analysis:
- guess the key length (based on count of equal chars)
- guess the key (base on knowledge of most frequent char)
Usage:
xortool [-x] [-m MAX-LEN] [FILE]
xortool [-x] [-l LEN] [-c CHAR | -b | -o] [FILE]
xortool [-x] [-m MAX-LEN| -l LEN] [-c CHAR | -b | -o] [FILE]
xortool [-h | --help]
xortool --version
Options:
-x --hex input is hex-encoded str
-l LEN, --key-length=LEN length of the key
-m MAX-LEN, --max-keylen=MAX-LEN maximum key length to probe [default: 65]
-c CHAR, --char=CHAR most frequent char (one char or hex code)
-b --brute-chars brute force all possible most frequent chars
-o --brute-printable same as -b but will only check printable chars
-h --help show this help
Examples:
xortool file.bin
xortool -l 11 -c 20 file.bin
xortool -x -c ' ' file.hex
"""
from operator import itemgetter
import os
import string
import xortool
from xortool.colors import *
from xortool.routine import *
from xortool.args import parse_parameters, ArgError
DIRNAME = 'xortool_out' # here plaintexts will be placed
PARAMETERS = dict()
class AnalysisError(Exception):
pass
def main():
global PARAMETERS
try:
PARAMETERS = parse_parameters(__doc__, xortool.__version__)
ciphertext = get_ciphertext()
update_key_length(ciphertext)
if PARAMETERS["brute_chars"]:
try_chars = range(256)
elif PARAMETERS["brute_printable"]:
try_chars = map(ord, string.printable)
elif PARAMETERS["most_frequent_char"] != None:
try_chars = [PARAMETERS["most_frequent_char"]]
else:
die(C_WARN +
"Most possible char is needed to guess the key!" +
C_RESET)
(probable_keys,
key_char_used) = guess_probable_keys_for_chars(ciphertext, try_chars)
print_keys(probable_keys)
produce_plaintexts(ciphertext, probable_keys, key_char_used)
except IOError as err:
print C_FATAL + "[ERROR] Can't load file:\n\t", err, C_RESET
except ArgError as err:
print C_FATAL + "[ERROR] Bad argument:\n\t", err, C_RESET
except MkdirError as err:
print C_FATAL + "[ERROR] Can't create directory:\n\t", err, C_RESET
except AnalysisError as err:
print C_FATAL + "[ERROR] Analysis error:\n\t", err, C_RESET
else:
return
cleanup()
# -----------------------------------------------------------------------------
# LOADING CIPHERTEXT
# -----------------------------------------------------------------------------
def get_ciphertext():
"""
Load ciphertext from a file or stdin and hex-decode if needed
"""
ciphertext = load_file(PARAMETERS["filename"])
if PARAMETERS["input_is_hex"]:
ciphertext = decode_from_hex(ciphertext)
return ciphertext
# -----------------------------------------------------------------------------
# KEYLENGTH GUESSING SECTION
# -----------------------------------------------------------------------------
def update_key_length(text):
"""
Guess length of the key if it's not set. (Updates PARAMETERS)
"""
global PARAMETERS
if PARAMETERS["known_key_length"]:
return
PARAMETERS["known_key_length"] = guess_key_length(text)
return
def guess_key_length(text):
"""
Try key lengths from 1 to max_key_length and print local maximums.
Set key_length to the most possible if it's not set by user.
"""
fitnesses = calculate_fitnesses(text)
if not fitnesses:
raise AnalysisError("No candidates for key length found! Too small file?")
print_fitnesses(fitnesses)
guess_and_print_divisors(fitnesses)
return get_max_fitnessed_key_length(fitnesses)
def calculate_fitnesses(text):
"""
Calc. fitnesses for each keylen
"""
prev = 0
pprev = 0
fitnesses = []
for key_length in range(1, PARAMETERS["max_key_length"] + 1):
fitness = count_equals(text, key_length)
# smaller key-length with nearly the same fitness is preferable
fitness = (float(fitness) /
(PARAMETERS["max_key_length"] + key_length ** 1.5))
if pprev < prev and prev > fitness: # local maximum
fitnesses += [(key_length - 1, prev)]
pprev = prev
prev = fitness
if pprev < prev:
fitnesses += [(key_length - 1, prev)]
return fitnesses
def print_fitnesses(fitnesses):
print "The most probable key lengths:"
# top sorted by fitness, but print sorted by length
fitnesses.sort(key=itemgetter(1), reverse=True)
top10 = fitnesses[:10]
best_fitness = top10[0][1]
top10.sort(key=itemgetter(0))
fitness_sum = calculate_fitness_sum(top10)
for key_length, fitness in top10:
s1 = str(key_length).rjust(4, " ")
s2 = str(round(100 * fitness * 1.0 / fitness_sum, 1)) + "%"
if fitness == best_fitness:
print (C_BEST_KEYLEN + s1 + C_RESET + ": "
+ C_BEST_PROB + s2 + C_RESET)
else:
print (C_KEYLEN + s1 + C_RESET + ": "
+ C_PROB + s2 + C_RESET)
return
def calculate_fitness_sum(fitnesses):
return sum([f[1] for f in fitnesses])
def count_equals(text, key_length):
"""
count equal chars count for each offset and sum them
"""
equals_count = 0
if key_length >= len(text):
return 0
for offset in range(key_length):
chars_count = chars_count_at_offset(text, key_length, offset)
equals_count += max(chars_count.values()) - 1 # why -1? don't know
return equals_count
def guess_and_print_divisors(fitnesses):
"""
Prints common divisors and returns the most common divisor
"""
divisors_counts = [0] * (PARAMETERS["max_key_length"] + 1)
for key_length, fitness in fitnesses:
for number in range(3, key_length + 1):
if key_length % number == 0:
divisors_counts[number] += 1
max_divisors = max(divisors_counts)
limit = 3
ret = 2
for number, divisors_count in enumerate(divisors_counts):
if divisors_count == max_divisors:
print "Key-length can be " + C_DIV + str(number) + "*n" + C_RESET
ret = number
limit -= 1
if limit == 0:
return ret
return ret
def get_max_fitnessed_key_length(fitnesses):
max_fitness = 0
max_fitnessed_key_length = 0
for key_length, fitness in fitnesses:
if fitness > max_fitness:
max_fitness = fitness
max_fitnessed_key_length = key_length
return max_fitnessed_key_length
def chars_count_at_offset(text, key_length, offset):
chars_count = dict()
for pos in range(offset, len(text), key_length):
c = text[pos]
if c in chars_count:
chars_count[c] += 1
else:
chars_count[c] = 1
return chars_count
# -----------------------------------------------------------------------------
# KEYS GUESSING SECTION
# -----------------------------------------------------------------------------
def guess_probable_keys_for_chars(text, try_chars):
"""
Guess keys for list of characters.
"""
probable_keys = []
key_char_used = {}
for c in try_chars:
keys = guess_keys(text, c)
for key in keys:
key_char_used[key] = c
if key not in probable_keys:
probable_keys.append(key)
return probable_keys, key_char_used
def guess_keys(text, most_char):
"""
Generate all possible keys for key length
and the most possible char
"""
key_length = PARAMETERS["known_key_length"]
key_possible_bytes = [[] for _ in range(key_length)]
for offset in range(key_length): # each byte of key<
chars_count = chars_count_at_offset(text, key_length, offset)
max_count = max(chars_count.values())
for char in chars_count:
if chars_count[char] >= max_count:
key_possible_bytes[offset].append(chr(ord(char) ^ most_char))
return all_keys(key_possible_bytes)
def all_keys(key_possible_bytes, key_part="", offset=0):
"""
Produce all combinations of possible key chars
"""
keys = []
if offset >= len(key_possible_bytes):
return [key_part]
for c in key_possible_bytes[offset]:
keys += all_keys(key_possible_bytes, key_part + c, offset + 1)
return keys
def print_keys(keys):
if not keys:
print "No keys guessed!"
return
s1 = C_COUNT + str(len(keys)) + C_RESET
s2 = C_COUNT + str(len(keys[0])) + C_RESET
print "{} possible key(s) of length {}:".format(s1, s2)
for key in keys[:5]:
print C_KEY + repr(key)[1:-1] + C_RESET
if len(keys) > 10:
print "..."
# -----------------------------------------------------------------------------
# RETURNS PERCENTAGE OF PRINTABLE CHARS
# -----------------------------------------------------------------------------
def percentage_printable(text):
x = 0.0
for c in text:
if c in string.printable:
x += 1
return x / len(text)
# -----------------------------------------------------------------------------
# PRODUCE OUTPUT
# -----------------------------------------------------------------------------
def produce_plaintexts(ciphertext, keys, key_char_used):
"""
Produce plaintext variant for each possible key,
creates csv files with keys, percentage of printable
characters and used most frequent character
"""
cleanup()
mkdir(DIRNAME)
# this is split up in two files since the
# key can contain all kinds of characters
fn_key_mapping = "filename-key.csv"
fn_perc_mapping = "filename-char_used-perc_printable.csv"
key_mapping = open(os.path.join(DIRNAME, fn_key_mapping), "w")
perc_mapping = open(os.path.join(DIRNAME, fn_perc_mapping), "w")
key_mapping.write("file_name;key_repr\n")
perc_mapping.write("file_name;char_used;perc_printable\n")
threshold_printable = 95
count_printable = 0
for index, key in enumerate(keys):
key_index = str(index).rjust(len(str(len(keys) - 1)), "0")
key_repr = repr(key)[1:-1].replace("/", "\\x2f")
if not is_linux():
key_repr = alphanum(key)
file_name = os.path.join(DIRNAME, key_index + ".out")
dexored = dexor(ciphertext, key)
perc = round(100 * percentage_printable(dexored))
if perc > threshold_printable:
count_printable += 1
key_mapping.write("{};{}\n".format(file_name, key_repr))
perc_mapping.write("{};{};{}\n".format(file_name,
repr(key_char_used[key]),
perc))
f = open(file_name, "wb")
f.write(dexored)
f.close()
key_mapping.close()
perc_mapping.close()
s1 = C_COUNT + str(count_printable) + C_RESET
s2 = C_COUNT + str(round(threshold_printable)) + C_RESET
print "Found {} plaintexts with {}%+ printable characters".format(s1, s2)
print "See files {}, {}".format(fn_key_mapping, fn_perc_mapping)
return
def cleanup():
if os.path.exists(DIRNAME):
rmdir(DIRNAME)
return
if __name__ == "__main__":
main()

View file

@ -1,116 +0,0 @@
#!/usr/bin/env python
#-*- coding:utf-8 -*-
"""
xor strings
options:
-s - string with \\xAF escapes
-r - raw string
-h - hex-encoded string (non-letterdigit chars are stripped)
-f - read data from file (- for stdin)
-n - no newline at the end
--no-cycle / --nc - pad smaller strings with null bytes
example: xor -s lol -h 414243 -f /etc/passwd
author: hellman ( hellman1908@gmail.com )
"""
import sys
import string
import getopt
DATA_OPTS = "s:r:h:f:"
HEXES = set("0123456789abcdefABCDEF")
def main():
nocycle = False
nonewline = False
try:
opts, args = getopt.getopt(sys.argv[1:], "n" + DATA_OPTS, ["no-cycle", "nc"])
datas = []
for c, val in opts:
if c in ("--no-cycle", "--nc"):
nocycle = True
elif c == "-n":
nonewline = True
else:
v = arg_data(c, val)
if v is None:
raise getopt.GetoptError("unknown option %s" % c)
datas.append(v)
if not datas:
raise getopt.GetoptError("no data given")
except getopt.GetoptError as e:
print >>sys.stderr, "error:", e
print >>sys.stderr, __doc__
quit()
sys.stdout.write(xor(datas, nocycle=nocycle))
if not nonewline:
sys.stdout.write("\n")
def xor(args, nocycle=False):
maxlen = max(map(len, args))
res = [0] * maxlen
if nocycle:
for s in args:
for i in xrange(len(s)):
res[i] ^= ord(s[i])
else:
for s in args:
slen = len(s)
for i in xrange(maxlen):
res[i] ^= ord(s[i % slen])
return "".join(map(chr, res))
def from_str(s):
res = ""
i = 0
while True:
if i + 4 > len(s):
break
if s[i+1] == "x" and s[i+2] in HEXES and s[i+3] in HEXES:
res += chr(int(s[i+2:i+4], 16))
i += 4
else:
res += s[i]
i += 1
res += s[i:]
return res
def from_hex(s):
res = ""
for c in s:
if c in HEXES:
res += c
elif c in string.ascii_letters:
raise ValueError("Bad splitters (alphanum)")
return res.decode("hex")
def from_file(s):
if s == "-":
return sys.stdin.read()
return open(s, "rb").read()
def arg_data(opt, s):
if opt == "-s":
return from_str(s)
elif opt == "-r":
return s
elif opt == "-h":
return from_hex(s)
elif opt == "-f":
return from_file(s)
return None
if __name__ == '__main__':
main()