
'''
This script was hacked together using Major Malfunctions cab.py and cmsb.py, licenses from those as follows:

<CMSB>
# 
# cmsb.py: Create MagStripe Binary
# Convert ASCII data to ABA/IATA binary with LRC
# Inspired by dmsb.c by Joseph Battaglia <sephail@sephail.net>
# 
# Copyright 2006,2007 Major Malfunction <majormal@pirate-radio.org>
# version 0.1 (IATA only)
#   http://www.alcrypto.co.uk/
#   Distributed under the terms of the GNU General Public License v2
# version 0.2 (add ABA capability, characterset checking)
#   Parts Copyright 2007 Mansour Moufid <mmoufid@connect.carleton.ca>
#   Distributed under the terms of the GNU General Public License v3

<CAB>
# cab.py: Create Aiken Biphase
# create a WAV file with arbitrary data in it
#
# Copyright(c) 2006, Major Malfunction <majormal@pirate-radio.org>
# http://www.alcrypto.co.uk
#
# inspired by 'dab.c' by Joseph Battaglia <sephail@sephail.net>
#
#   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.
#
# version 0.1:
#	just get the thing working with fixed WAV and other parameters!


Password gen stuff thanks to Nadeem Douba ( @ndouba )
'''
import sys
import string
from operator import *
import wave
import sys
from struct import *
from math import *


def _baseN(num, base, numerals):
    if not num:
        return numerals[0]

    if num < 0:
        return '-' + _baseN((-1) * num, base, numerals)

    if not 2 <= base <= len(numerals):
        raise ValueError('Base must be between 2-%d' % len(numerals))

    left_digits = num // base

    if left_digits == 0:
        return numerals[num % base]
    else:
        return _baseN(left_digits, base, numerals) + numerals[num % base]


def baseN(num, numerals="0123456789abcdefghijklmnopqrstuvwxyz", padding=0):

    n = _baseN(num, len(numerals), numerals)
    l = len(n)

    if l < padding:
        n = '%s%s' % (numerals[0] * (padding - l), n)
    return n

	
	
def createSquareWav(wavFile,freq,data,reverse,delay):
	
	
	frequency= int(freq) - 1
	

	if reverse == True:
		newdata= []
		n= len(data) - 1
		while n >= 0:
			newdata.append(data[n])
			n= n - 1
		data= newdata

	peak= 32767
	wavedata = []
	#Trailing space
	for x in range(int(22050 * delay)):
		wavedata.append('\x00\x00')
		#wavFile.writeframes('\x00\x00')

	for x in range(20):
		wavedata.append(pack("h",0))
		#wavFile.writeframes(pack("h",0))

	# write the actual data
	# square wave for now
	n= 0
	writedata= peak
	while n < len(data):
		if data[n] == '1':
			for x in range(2):
				writedata= -writedata
				for y in range(frequency/4):
					wavedata.append(pack("h",writedata))
					#wavFile.writeframes(pack("h",writedata))
		if data[n] == '0':
			writedata= -writedata
			for y in range(frequency/2):
				wavedata.append(pack("h",writedata))
				#wavFile.writeframes(pack("h",writedata))
				
		n= n + 1
	
	#for x in range(32000):
	#	wavFile.writeframes('\x00\x00')
	for x in range(int(22050 * delay)):
		wavedata.append('\x00\x00')
		
	#Doing it this way takes some tests I did from 1min 15secs to 2seconds!!!!!!!
	value_str = ''.join(wavedata)
	wavFile.writeframes(value_str)
	
def createAikenBiphase(tracknum,data,padding):
	if int(tracknum) == 1:
		bits = 7
		base= 32
		max= 63
	elif int(tracknum) == 2 or int(tracknum) == 3:
		bits = 5
		base= 48
		max= 15

	zero = ''
	lrc = []

	for x in range(bits):
		zero += "0"
		lrc.append(0)
	output = ''


	#padding = 0

	for x in range(padding):
		output += zero

	for x in range( len(data) ):
		raw = ord(data[x]) - base
		if raw < 0 or raw > max:
			print 'Illegal character:', chr(raw+base)
			sys.exit(False)
		parity = 1
		for y in range(bits-1):
			output += str(raw >> y & 1)
			parity += raw >> y & 1
			lrc[y] = xor(lrc[y], raw >> y & 1)
		output += chr((parity % 2) + ord('0'))

	parity = 1
	for x in range(bits - 1):
		output += chr(lrc[x] + ord('0'))
		parity += lrc[x]
	output += chr((parity % 2) + ord('0'))

	

	return output
	
if len(sys.argv) < 5:
	print "createWavs.py v0.01"
	print "Usage: %s <TRACK No.> <DATA> OutputFile.wav  <PADDING> <Samples> <[r]everse> <delay_at_front_and_back> " % sys.argv[0]
	print "* = Try all in range for track, eg, T2 = 0,1,2,3,4,5,6,7,8,9,:,;,<,=,>,?"
	
	sys.exit(False)

print "-------------------------------------------------"
print "      Marty McFly's Wav Generator                "
print "      Generating Aiken Biphase Wav Files         "
print "         by Andrew MacPherson (@AndrewMohawk)    "
print "-------------------------------------------------"
tracknum = int(sys.argv[1])
data = sys.argv[2]
padding = 0

if(len(sys.argv) > 4):
	padding = int(sys.argv[4])

samplesPerBit = 15
if(len(sys.argv) > 5):
	samplesPerBit = int(sys.argv[5])

reverse = False
if(len(sys.argv) > 6) and (sys.argv[6] == 'r'):
	reverse = True
delay=0
if(len(sys.argv) > 7):
	delay = float(sys.argv[7])
	
	
results = []
numStars = data.count("*")
print "[+] Found %s number of brute force fields" % numStars
bruteForceList = [];
if(tracknum == 1):
	for z in range(32,95):
		bruteForceList.append(chr(z))
if(tracknum == 2 or tracknum ==3):
	for z in range(48,64):
		bruteForceList.append(chr(z))


		
		
#print bruteForceList
#exit(0)
#bruteForceList = ['A','B']
if (numStars > 0):
	print "[+] Generating Aiken Biphase... "
	pfmt = data
	i = 0
	while True:
		n = baseN(i, bruteForceList, numStars)
		if len(n) > numStars:
			break
		tmp = pfmt
		for c in n:
			tmp = tmp.replace('*', c, 1)
			
		#results.append(tmp)
		results.append(createAikenBiphase(tracknum,tmp,padding))
		i += 1
else:
	
	results.append(createAikenBiphase(tracknum,data,padding))
	

print "[+] Generated %s Results" % len(results)
print "[+] Building consecutive wav file.."

wavFile=wave.open(sys.argv[3],"w")
params= (1, 2, 22050, 0L, 'NONE', 'not compressed')
wavFile.setparams(params)
for r in results:
	createSquareWav(wavFile,samplesPerBit,r,reverse,delay)

wavFile.close()