#!/usr/bin/env python # RSA decode def unmakedes(x,d=11,n=4097): return pow(x,d,n) # Lots of scrambling def undoit(x): return ((7-x)*3+5)%8 def undotooit(x): return ((13-x)*5)%8 #(defun un-permute-it (x) # (setf new 0) # (dotimes (temp 8) # (if (= (mod x 2) 1) # (setf new (+ new (expt 2 (un-do-it temp))))) # (setf x (/ (- x (mod x 2)) 2))) # (setf x new)) #(defun un-waymute-it (x) # (setf new 0) # (dotimes (temp 8) # (if (= (mod x 2) 1) # (setf new (+ new (expt 2 (un-do-it-too temp)))) # ()) # (setf x (/ (- x (mod x 2)) 2))) # (setf x new)) def unpermuteit(x): return sum(2**undoit(i) for i in filter(lambda y:(x>>y)&1==1,range(8))) def unwaymuteit(x): return sum(2**undotooit(i) for i in filter(lambda y:(x>>y)&1==1,range(8))) #(defun un-happenin (x1 y1 z1) # (setf this-num (un-make-des (+ x1 (* (mode y1 little) lot))) # that-num (un-make-des (+ (* z1 little) (/(- y1 (mod y1 little)) little)))) # (setf temp1 (mod this-num lot) # temp2 (+ (/ (- this-num temp1) lot) (* (mod that-num little) little)) # temp3 (/ (- that-num (mod that-num little)) little))) #Group 3 8-bit chars into 2 12 bit numbers, RSA-decrypt them and split result back into 3 numbers def unhappenin (cell): (x1,y1,z1)=cell d1=unmakedes(((y1&0xf)<<8)+x1) d2=unmakedes((z1<<4)+(y1>>4)) return (d1&0xff,((d2&0xf)<<4)+(d1>>8),d2>>4) # Main decryption function # Read 3-byte cells, permutate mid character, RSA-decrypt it and permutate all members of the cell def unrollthetext(thetext,wend=-1,celllength=3): rc="" if wend<0: wend=len(thetext) numcells=wend/celllength for i in range(numcells): cell=(ord(thetext[3*i]),unwaymuteit(ord(thetext[3*i+1])),ord(thetext[3*i+2])) rc+="%c%c%c" % tuple(map(unpermuteit,unhappenin(cell))) return rc # --- END OF AGRIPPA DECRYPTION ALGORITHS --- # Read codebitsz bits at position idx from a stream def parsestream(arr,idx, codebitsz): (offs,idx)=(8-(idx&7),idx//8) rc=ord(arr[idx])&((1<8: rc=rc*256+ord(arr[idx]) (offs,idx)=(offs-8,idx+1) if offs!=0: rc=rc*256+ord(arr[idx]) rc=rc>>(8-offs) return rc # Classical Lempel-Ziv-Welch decompressor def LZWDecode(stream): (rc,conj,idx,codebitsz)=("","",0,9) dict=map(chr,range(256)) dict.append(chr(0)) while idx0: dict.append(conj+dict[e][0]) rc+=dict[e] conj=dict[e] if codebitsz<12 and len(dict)==1<1: fname=argv[1] if not exists(fname): print "Failed to open %s: Please put original (or modified) Agrippa executable to the same folder as %s" % (fname, argv[0]) print "On Mac OS X Agrippa can be extracted from fd0-agrippa.dmg using following commands:" print "\t$ hdiutil attach fd0_agrippa.dmg" print "\t$ cp /Volumes/Agrippa\(a\ book\ of\ the\ dead\)/Agrippa ." print "\t$ hdiutil detach /Volumes/Agrippa\(a\ book\ of\ the\ dead\)/" print "Or pass the path to Agrippa binary as first argument to the script" exit(0) print "Reading %s..." % fname, data=open(fname).read() print "%d bytes read" % len(data) print "Decompressing LISP binary...", decompressed=LZWDecode(data[0x80d1c:]) print "%d bytes decompressed" % len(decompressed) print "\n\n\nAnd now, TheText\n\n:" print unrollthetext(decompressed[4875:4875+3306*3]).replace("\r","\n")