#!/usr/bin/env python
# River City Ransom password decrypter
# v0.0 - 09.10.2004
# author: Jerry McMahan Jr. (jerry@ensomnya.net)
#
# This program is freely redistributable and freely modifyable, provided
# any derivative works are also made freely redistributable and
# freely modifyable.
import cgi, cgitb, string
def bcd2dec(num):
""" converts BCD to decimal"""
return (num / 16)*10 + num % 16
def dec2bcd(num):
"""converts decimal to BCD"""
return num % 10 + (num/10)*16
keystring = (13, 5, 24, 7, 11, 17, 29, 16, 21, 19, 23,
9, 15, 25, 31, 12, 20, 5, 3, 22, 6, 12,
18, 7, 10, 11, 27, 18, 14, 13, 12, 24, 17)
textval_reverse = {
255:"B'",
254:"A'",
253:"9",
252:"8",
251:"7",
250:"6",
249:"5",
248:"4",
247:"3",
246:"2",
245:"1",
244:"0",
243:"z",
242:"y",
241:"x",
240:"w",
239:"v",
238:"u",
237:"t",
236:"s",
235:"r",
234:"q",
233:"p",
232:"o",
231:"n",
230:"m",
229:"l",
228:"k",
227:"j",
226:"i",
225:"h",
224:"g",
223:"f",
222:"e",
221:"d",
220:"c",
219:"b",
218:"a",
217:"Z",
216:"Y",
215:"X",
214:"W",
213:"V",
212:"U",
211:"T",
210:"S",
209:"R",
208:"Q",
207:"P",
206:"O",
205:"N",
204:"M",
203:"L",
202:"K",
201:"J",
200:"I",
199:"H",
198:"G",
197:"F",
196:"E",
195:"D",
194:"C",
193:"B",
192:"A" }
textval = {
"B'":255,
"#":255, # same as B'
"A'":254,
"@":254, # same as A'
"9":253,
"8":252,
"7":251,
"6":250,
"5":249,
"4":248,
"3":247,
"2":246,
"1":245,
"0":244,
"z":243,
"y":242,
"x":241,
"w":240,
"v":239,
"u":238,
"t":237,
"s":236,
"r":235,
"q":234,
"p":233,
"o":232,
"n":231,
"m":230,
"l":229,
"k":228,
"j":227,
"i":226,
"h":225,
"g":224,
"f":223,
"e":222,
"d":221,
"c":220,
"b":219,
"a":218,
"Z":217,
"Y":216,
"X":215,
"W":214,
"V":213,
"U":212,
"T":211,
"S":210,
"R":209,
"Q":208,
"P":207,
"O":206,
"N":205,
"M":204,
"L":203,
"K":202,
"J":201,
"I":200,
"H":199,
"G":198,
"F":197,
"E":196,
"D":195,
"C":194,
"B":193,
"A":192 }
inventory = {
0 :'NOTHING',
1 :'DONUT',
2 :'MUFFIN',
3 :'BAGEL',
4 :'HONEY BUN',
5 :'CROISSANT',
6 :'SUGAR',
7 :'TOLL HOUSE',
8 :'MAPLE PECAN',
9 :'OATMEAL',
10 :'BROWNIE',
11 :'MINT GUM',
12 :'LOLLY POP',
13 :'JAW BREAKER',
14 :'ROCK CANDY',
15 :'FUDGE BAR',
16 :'SALAD PARIS',
17 :'ONION SOUP',
18 :'CORNISH HEN',
19 :'VEAL WALLE',
20 :'VITA-MINTS',
21 :'DIGESTOL',
22 :'RECHARGE!',
23 :'KARMA JOLT',
24 :'OMNI ELIXER',
25 :'DATE SAVER',
26 :'LOVE POTION',
27 :'ANTEDOTE 12',
28 :'R & B',
29 :'ROCK',
30 :'POP',
31 :'SOUL',
32 :'CLASSICAL',
33 :'SNEAKERS',
34 :'BOAT SHOES',
35 :'LOAFERS',
36 :'ARMY BOOTS',
37 :'TEXAS BOOTS',
38 :'SLIPPERS',
39 :'THONGS',
40 :'SANDALS',
41 :'MOD BOOTS',
42 :'INSOLES',
43 :'MAZE CRAZE',
44 :'DECATHLETE',
45 :'HYPER BALL',
46 :'TECHNO BELT',
47 :'TEDDY BEAR',
48 :'STONE HANDS',
49 :'DRAGON FEET',
50 :'GRAND SLAM',
51 :'ACRO CIRCUS',
52 :'JAVELIN MAN',
53 :'FATAL STEPS',
54 :'SCANDAL RAG',
55 :'COMIC TIMES',
56 :'MYSTIC SEER',
57 :'NUCLEAR SPY',
58 :'INDIAN LORE',
59 :'EXCALIBER',
60 :'ZEUS WAND',
61 :'RODAN WING',
62 :'GOLD MEDAL',
63 :'ISIS SCROLL',
64 :'SIRLOIN',
65 :'RIB-EYE',
66 :'T-BONE',
67 :'LAMB LEG',
68 :'MERV BURGER',
69 :'CHEESE MERV',
70 :'FISH MERV',
71 :'MONDO MERV',
72 :'MILK',
73 :'ICED TEA',
74 :'SODA',
75 :'MERV MALT',
76 :'MERV FRIES',
77 :'MERV RINGS',
78 :'APPLE PIES',
79 :'SPICY CHILI',
80 :'SMILE',
81 :'CHICKWICH',
82 :'DARK MEAT',
83 :'WHITE MEAT',
84 :'COMBINATION',
85 :'LEMONADE',
86 :'GRAVY',
87 :'BISCUITS',
88 :'CORN COBBER',
89 :'COLE SLAW',
90 :'COFFEE',
91 :'TEA',
92 :'HOT COCOA',
93 :'PANCAKES',
94 :'WAFFLES',
95 :'ICE CREAM',
96 :'ROMAN SHAKE',
97 :'COLA FLOAT',
98 :'NERO PIZZA',
99 :'LASAGNA',
100 :'FRESH JUICE',
101 :'LEMON TEA',
102 :'HERBAL TEA',
103 :'CARROT CAKE',
104 :'POUND CAKE',
105 :'EGG',
106 :'OCTOPUS',
107 :'SQUID',
108 :'CONGER EEL',
109 :'PRAWN',
110 :'SALMON',
111 :'ARK SHELL',
112 :'SEA URCHIN',
113 :'HALIBUT',
114 :'SWORDFISH',
115 :'SALAD ROLL',
116 :'TUNA ROLL',
117 :'SHRIMP ROLL',
118 :'MIXED ROLL',
119 :'EGG ROLL',
120 :'FRIED RICE',
121 :'GARLIC PORK',
122 :'PEPPER BEEF',
123 :'CHOW MEIN',
124 :'SAUNA',
125 :'NO THANKS',
126 :'NOTHING (ALT)',
127 :'MAIN MENU'}
password_invalid = False
password_error = "Password Valid"
# enable cgi debugging
# cgitb.enable()
# read cgi data
form = cgi.FieldStorage()
password_text = form.getvalue("password")
# eliminate white space and find occurences of "A'" and "B'"
password_split = password_text.split()
password_strip = ""
for excerpt in password_split:
password_strip += excerpt
i_max = len(password_strip)
password_chars = []
for i in range(i_max-1):
if password_strip[i] == "'":
continue
if (password_strip[i+1] == "'"):
if (password_strip[i] == 'A' or password_strip[i] == 'B'):
password_chars.append(password_strip[i]+"'")
else:
password_invalid = True
password_error = "' used on invalid character"
else:
password_chars.append(password_strip[i])
if (password_strip[i_max-1] != "'"):
password_chars.append(password_strip[i_max-1])
# check for errors
for i in range(33 - len(password_chars)):
password_chars.append("A")
if not password_invalid:
password_invalid = True
password_error = "Password too short"
password_clear = []
i=0
if textval.has_key(password_chars[32]):
key = textval[password_chars[32]] - 192
else:
key = 0
if not password_invalid:
password_invalid = True
password_error = "Invalid character for password key"
if key >= 32:
key = 0
if not password_invalid:
password_invalid = True
password_error = "Bad key value for password"
# decrypt password info
i=0
for char in password_chars:
if i >= 33:
if not password_invalid:
password_invalid = True
password_error = "Password too long"
break
if not textval.has_key(char):
password_clear.append(0)
if not password_invalid:
password_invalid = True
password_error = "Invalid character entered"
else:
val = (textval[char]-192)^(keystring[i]+key)
password_clear.append(val)
i += 1
# extract data from password_clear
punch = password_clear[0] & 0x3f
kick = password_clear[1] & 0x3f
weapon = password_clear[2] & 0x3f
throwing = password_clear[3] & 0x3f
agility = password_clear[4] & 0x3f
defense = password_clear[5] & 0x3f
strength = password_clear[6] & 0x3f
will = password_clear[7] & 0x3f
stamina = ((password_clear[8]&0x3f) + ((password_clear[10] >> 2) & 0x3)*64)&0x7f
maxpwr = ((password_clear[9]&0x3f) + (password_clear[10] & 0x3)*64)&0x7f
skills = password_clear[11] & 0x3f
cents = (password_clear[12]&0x3f) + ((password_clear[15] >> 4) & 0x3)*64
ones = (password_clear[13]&0x3f) + ((password_clear[15] >> 2) & 0x3)*64
hundreds = (password_clear[14]&0x3f) + (password_clear[15] & 0x3)*64
inv1 = (password_clear[16]&0x3f) + ((password_clear[18] >> 2) & 0x3)*64
inv2 = (password_clear[17]&0x3f) + ((password_clear[18] ) & 0x3)*64
inv3 = (password_clear[19]&0x3f) + ((password_clear[21] >> 2) & 0x3)*64
inv4 = (password_clear[20]&0x3f) + ((password_clear[21] ) & 0x3)*64
inv5 = (password_clear[22]&0x3f) + ((password_clear[24] >> 2) & 0x3)*64
inv6 = (password_clear[23]&0x3f) + ((password_clear[24] ) & 0x3)*64
inv7 = (password_clear[25]&0x3f) + ((password_clear[27] >> 2) & 0x3)*64
inv8 = (password_clear[26]&0x3f) + ((password_clear[27] ) & 0x3)*64
boss1 = password_clear[28] & 0x3f
boss2 = password_clear[29] & 0x3f
boss3 = password_clear[30] & 0x3f
csum = password_clear[31] & 0x3f
dollars = bcd2dec(ones) + bcd2dec(hundreds) * 100
cents = bcd2dec(cents)
money = dollars + cents * .010
# calculate checksum and see if it matches the gathered checksum
csum_calc = 0
for i in range(31):
csum_calc += (password_clear[i] & 0x3f)
csum_calc &= 0x3f
csum_calc_char = textval_reverse[((key + keystring[31]) ^ csum_calc) + 192]
if csum_calc != csum:
if not password_invalid:
password_invalid = True
password_error = "Invalid checksum.
The game would reject this. The second to last letter should be " + '"' + csum_calc_char + '"' + '.'
# display html output
print "Content-type: text/html"
print
htmlfile = open('../projects/rcr_password/template.html')
html_text = htmlfile.read()
htmlfile.close()
html_begin = html_text[:html_text.find('_BODY_')]
html_end = html_text[html_text.find('_BODY_')+7:-1]
if not form.has_key("newstyle"):
print html_begin
print "Password Results
"
print "Password Possibly Invalid? :"
if password_invalid:
print "Yes
"
print "Error reported: " + password_error
print "
"
print "Parsed Input Data:
"
i = 0
for char in password_chars:
print char,
if (i+1) % 11 == 0:
print "
"
i += 1
print "
"
else:
print "No
"
print """
| """ print "Punch:" print " | " print punch print " |
| " print "Kick:" print " | " print kick print " |
| " print "Weapon:" print " | " print weapon print " |
| " print "Throwing:" print " | " print throwing print " |
| " print "Agility:" print " | " print agility print " |
| " print "Defense:" print " | " print defense print " |
| " print "Strength:" print " | " print strength print " |
| " print "Will Power:" print " | " print will print " |
| " print "Stamina:" print " | " print stamina print " |
| " print "Max Power:" print " | " print maxpwr print " |
| " print "Money:" print " | " print '$%3.2f'% money print ' |
| '
print " " print ' | |
| ' print "Skills:" print " | "
if skills & 1:
print "Stone Hands " if skills & 2: print "Dragon Feet " if skills & 4: print "Grand Slam " if skills & 8: print "Acro Circus " if skills & 16: print "Javelin Man " if skills & 32: print "Fatal Steps " print " |
| "
print " " print ' | |
| ' equip = '' if inv1 & 128: equip = '#' else: equip = '' print "Inventory Slot 1:" print " | " print equip + inventory[inv1&0x3f] print ' |
| ' equip = '' if inv2 & 128: equip = '#' else: equip = '' print "Inventory Slot 2:" print " | " print equip + inventory[inv2&0x3f] print ' |
| ' equip = '' if inv3 & 128: equip = '#' else: equip = '' print "Inventory Slot 3:" print " | " print equip + inventory[inv3&0x3f] print ' |
| ' equip = '' if inv4 & 128: equip = '#' else: equip = '' print "Inventory Slot 4:" print " | " print equip + inventory[inv4&0x3f] print ' |
| ' equip = '' if inv5 & 128: equip = '#' else: equip = '' print "Inventory Slot 5:" print " | " print equip + inventory[inv5&0x3f] print ' |
| ' equip = '' if inv6 & 128: equip = '#' else: equip = '' print "Inventory Slot 6:" print " | " print equip + inventory[inv6&0x3f] print ' |
| ' equip = '' if inv7 & 128: equip = '#' else: equip = '' print "Inventory Slot 7:" print " | " print equip + inventory[inv7&0x3f] print ' |
| ' equip = '' if inv8 & 128: equip = '#' else: equip = '' print "Inventory Slot 8:" print " | " print equip + inventory[inv8&0x3f] print ' |
| '
print " " print ' | |
| ' print "Bosses Defeated:" print " | "
if boss2 & 8:
print "Moose " if boss2 & 1: print "Roxy " if boss1 & 2: print "Benny " if boss1 & 1: print "Clyde " if boss3 & 1: print "Rocko " if boss3 & 2: print "Blade " if boss2 & 32: print "Turk " if boss2 & 16: print "Mojo " if boss1 & 4: print "Thor " if boss1 & 16: print "Ivan " if boss1 & 8: print "Otis " if boss1 & 32: print "Tex " if boss3 & 4: print "Randy " if boss3 & 8: print "Andy " if boss2 & 4: print "Cyndi " print " |
| "
print " " print ' | |
| ' print "Calculated Checksum:" print " | " print csum_calc, "(" + csum_calc_char + ")" print " |
| " print "Entered Checksum:" print " | " print csum, "(" + password_chars[31] + ")" print " |
| " print "Key:" print " | " print '%d (%s)' % (key, password_chars[-1]) print " |
| "
print " " print " |