├── .gitignore ├── LICENSE ├── README.md └── wipedicks.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Drew Bonasera 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wipedicks 2 | Wipe files and drives securely with randomized ASCII dicks. Because filling hard drives with zeros is really no fun 3 | 4 | ``` 5 | usage: wipedicks.py [-h] [-r] [-n num] [-w] Files [Files ...] 6 | 7 | Wipe files/devices with dicks 8 | 9 | positional arguments: 10 | Files Files, Directories, and Devices to wipe 11 | 12 | optional arguments: 13 | -h, --help show this help message and exit 14 | -r, --recursive Recursively parse folders for files to wipe 15 | -n num, --numrounds num 16 | The number of rounds to write the files 17 | -w, --wipefree Wipe the free space by creating a large file 18 | ``` 19 | 20 | Example: 21 | ``` 22 | [root@wipedicks ~]# xxd /dev/sdb | head 23 | 0000000: 3823 3d3d 447e 7e7e 2038 3d3d 3d3d 3d3d 8#==D~~~ 8====== 24 | 0000010: 3d3d 3d3d 447e 7e7e 2038 3d3d 3d3d 3d3d ====D~~~ 8====== 25 | 0000020: 3d3d 3d3d 3d3d 447e 7e20 3823 3d3d 3d3d ======D~~ 8#==== 26 | 0000030: 3d44 7e20 383d 3d3d 3d3d 3d3d 3d3d 447e =D~ 8=========D~ 27 | 0000040: 7e20 3823 3d3d 3d3d 3d3d 3d3d 3d3d 447e ~ 8#==========D~ 28 | 0000050: 7e20 3823 3d3d 447e 2038 3d3d 3d3d 3d3d ~ 8#==D~ 8====== 29 | 0000060: 3d3d 447e 7e20 3823 3d3d 3d3d 447e 2038 ==D~~ 8#====D~ 8 30 | 0000070: 3d3d 3d3d 3d3d 3d3d 3d3d 3d3d 4420 383d ============D 8= 31 | 0000080: 3d3d 3d3d 3d3d 3d3d 447e 7e20 3823 3d3d ========D~~ 8#== 32 | 0000090: 3d3d 3d3d 3d3d 3d3d 3d3d 447e 7e20 3823 ==========D~~ 8# 33 | ``` 34 | -------------------------------------------------------------------------------- /wipedicks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function, unicode_literals 3 | import os 4 | import threading 5 | import random 6 | try: 7 | random = random.SystemRandom() 8 | except: 9 | print('Using built in random number generator...') 10 | 11 | # This was generated using generate_dick_list() 12 | DICKS = ['8=D ', '8=D~ ', '8=D~~ ', '8=D~~~ ', '8==D ', '8==D~ ', '8==D~~ ', '8==D~~~ ', '8===D ', '8===D~ ', '8===D~~ ', '8===D~~~ ', '8====D ', '8====D~ ', '8====D~~ ', '8====D~~~ ', '8=====D ', '8=====D~ ', '8=====D~~ ', '8=====D~~~ ', '8======D ', '8======D~ ', '8======D~~ ', '8======D~~~ ', '8=======D ', '8=======D~ ', '8=======D~~ ', '8=======D~~~ ', '8========D ', '8========D~ ', '8========D~~ ', '8========D~~~ ', '8=========D ', '8=========D~ ', '8=========D~~ ', '8=========D~~~ ', '8==========D ', '8==========D~ ', '8==========D~~ ', '8==========D~~~ ', '8===========D ', '8===========D~ ', '8===========D~~ ', '8===========D~~~ ', '8============D ', '8============D~ ', '8============D~~ ', '8============D~~~ ', '8#=D ', '8#=D~ ', '8#=D~~ ', '8#=D~~~ ', '8#==D ', '8#==D~ ', '8#==D~~ ', '8#==D~~~ ', '8#===D ', '8#===D~ ', '8#===D~~ ', '8#===D~~~ ', '8#====D ', '8#====D~ ', '8#====D~~ ', '8#====D~~~ ', '8#=====D ', '8#=====D~ ', '8#=====D~~ ', '8#=====D~~~ ', '8#======D ', '8#======D~ ', '8#======D~~ ', '8#======D~~~ ', '8#=======D ', '8#=======D~ ', '8#=======D~~ ', '8#=======D~~~ ', '8#========D ', '8#========D~ ', '8#========D~~ ', '8#========D~~~ ', '8#=========D ', '8#=========D~ ', '8#=========D~~ ', '8#=========D~~~ ', '8#==========D ', '8#==========D~ ', '8#==========D~~ ', '8#==========D~~~ ', '8#===========D ', '8#===========D~ ', '8#===========D~~ ', '8#===========D~~~ ', '8#============D ', '8#============D~ ', '8#============D~~ ', '8#============D~~~ '] 13 | _fast_cache = '' 14 | _cache_count = 0 15 | 16 | 17 | def generate_dick_list(): 18 | dicks = [] 19 | for a in range(0, 2): 20 | for b in range(1, 13): 21 | for c in range(0, 4): 22 | dick = '8' 23 | dick += '#' * a 24 | dick += '=' * b 25 | dick += 'D' + '~' * c 26 | dick += ' ' 27 | dicks.append(dick) 28 | return dicks 29 | 30 | 31 | def rand_dick(): 32 | return random.choice(DICKS) 33 | 34 | 35 | def fast_rand_dick(): 36 | global _fast_cache 37 | global _cache_count 38 | if not _fast_cache or not _cache_count: 39 | _fast_cache = '' 40 | _cache_count = random.randint(1000, 10000) 41 | for _ in range(0, random.randint(150, 300)): 42 | _fast_cache += random.choice(DICKS) 43 | _cache_count -= 1 44 | return _fast_cache 45 | 46 | 47 | def wipe(dev, rounds=1): 48 | try: 49 | size = os.path.getsize(dev) 50 | except: 51 | size = 0 52 | 53 | if size == 0: 54 | for i in range(0, rounds): 55 | try: 56 | f = open(dev, 'w') 57 | except Exception as e: 58 | print('ERROR:', dev, e) 59 | return False 60 | 61 | while True: 62 | try: 63 | f.write(rand_dick()) 64 | except IOError: 65 | f.close() 66 | break 67 | else: 68 | for i in range(0, rounds): 69 | try: 70 | f = open(dev, 'w') 71 | except Exception as e: 72 | print('ERROR:', dev, e) 73 | return False 74 | 75 | dlen = 0 76 | while dlen < size: 77 | dick = rand_dick() 78 | dlen += len(dick) 79 | try: 80 | f.write(dick) 81 | except IOError: 82 | f.close() 83 | break 84 | 85 | dlen = 0 86 | dick = '' 87 | while dlen < len(dev): 88 | dick += rand_dick() 89 | dlen += len(dick) 90 | try: 91 | os.rename(dev, dick) 92 | dev = dick 93 | except: 94 | pass 95 | 96 | os.remove(dev) 97 | 98 | return True 99 | 100 | 101 | def parse_dir(directory, recursive=False): 102 | """ 103 | Returns a list of files in a directory. 104 | 105 | dir - The directory to search 106 | recursive - If true it will recursively find files. 107 | """ 108 | filelist = [] 109 | for item in os.listdir(directory): 110 | item = os.path.join(directory, item) 111 | if os.path.isdir(item): 112 | if recursive: 113 | filelist.extend(parse_dir(item, recursive)) 114 | else: 115 | continue 116 | else: 117 | filelist.append(item) 118 | return filelist 119 | 120 | 121 | def parse_filelist(FileList, recursive=False): 122 | """ 123 | Takes a list of files and directories and returns a list of files. 124 | 125 | FileList - A list of files and directories. Files in each directory will be returned 126 | recursive - If true it will recursively find files in directories. 127 | """ 128 | filelist = [] 129 | for item in FileList: 130 | if os.path.isdir(item): 131 | if recursive: 132 | filelist.extend(parse_dir(item, recursive)) 133 | else: 134 | print('WARNING:', item, 'is a directory and recursive is off.') 135 | elif os.path.exists(item): 136 | filelist.append(item) 137 | else: 138 | pass 139 | return filelist 140 | 141 | 142 | def _main(): 143 | import argparse 144 | parser = argparse.ArgumentParser(description="Wipe files/devices with dicks") 145 | parser.add_argument("-r", "--recursive", action="store_true", help="Recursively parse folders for files to wipe") 146 | parser.add_argument('-n', '--numrounds', help="The number of rounds to write the files", required=False, metavar="num", default=1, type=int) 147 | parser.add_argument("-w", "--wipefree", action="store_true", help="Wipe the free space by creating a large file") 148 | parser.add_argument("-s", "--slow", action="store_true", help="Use more randomness, tends to be slower") 149 | parser.add_argument('Files', help="Files, Directories, and Devices to wipe", nargs='+') 150 | args = parser.parse_args() 151 | 152 | if not args.slow: 153 | global rand_dick 154 | rand_dick = fast_rand_dick 155 | 156 | file_list = parse_filelist(args.Files) 157 | thread_list = [] 158 | kwargs = {'rounds': args.numrounds} 159 | if args.wipefree: 160 | file_list.append('dick.tmp') 161 | for f in file_list: 162 | t = threading.Thread(target=wipe, args=(f,), kwargs=kwargs) 163 | t.daemon = True 164 | t.start() 165 | thread_list.append(t) 166 | 167 | for t in thread_list: 168 | t.join() 169 | 170 | 171 | if __name__ == '__main__': 172 | _main() 173 | --------------------------------------------------------------------------------