Läuft die Voice Acoustic VA-Remotecontrol (AllDSP AllControl) nativ unter Linux auf echtem wxGTK 3.0 — ohne Wine und ohne dekompilierten App-Code. Ausgeführt wird das unveränderte Python-2.7-Bytecode aus dem macOS-.app; C-Extensions (wxGTK/numpy/ scipy/PortAudio) kommen nativ aus Debian stretch. Enthält: va/ (Original-.pyc + pure-Python-Libs + Assets + launch.py mit den drei Linux-Fixes), Dockerfile/run.sh/entrypoint.sh, reference/ (dekompilierter Quellcode zum Debuggen) und README/STATUS. img.cache (378 MB, regenerierbar) ist per .gitignore ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
188 lines
6.1 KiB
Python
188 lines
6.1 KiB
Python
#/****************************************************************************
|
|
#* Software: FPDF_Protection *
|
|
#* Version: 1.02 *
|
|
#* Date: 2005/05/08 *
|
|
#* Author: Klemen VODOPIVEC *
|
|
#* License: Freeware *
|
|
#* *
|
|
#* You may use and modify this software as you wish as stated in original *
|
|
#* FPDF package. *
|
|
#* *
|
|
#* Thanks: Cpdf (http:#www.ros.co.nz/pdf) was my working sample of how to *
|
|
#* implement protection in pdf. *
|
|
#****************************************************************************/
|
|
from FPDF import *
|
|
import random, struct, md5, copy, array
|
|
|
|
class Protection(FPDF):
|
|
def __init__(this, orientation='P',unit='mm',format='A4'):
|
|
FPDF.__init__(this,orientation,unit,format)
|
|
this.encrypted=0 #whether document is protected
|
|
this.Uvalue='' #U entry in pdf document
|
|
this.Ovalue='' #O entry in pdf document
|
|
this.Pvalue='' #P entry in pdf document
|
|
this.enc_obj_id=0 #encryption object id
|
|
this.last_rc4_key='' #last RC4 key encrypted (cached for optimisation)
|
|
this.last_rc4_key_c='' #last RC4 computed key
|
|
this.encrypted=0
|
|
this.padding="\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A"
|
|
|
|
|
|
#/**
|
|
#* Function to set permissions as well as user and owner passwords
|
|
#*
|
|
#* - permissions is an array with values taken from the following list:
|
|
#* copy, print, modify, annot-forms
|
|
#* If a value is present it means that the permission is granted
|
|
#* - If a user password is set, user will be prompted before document is opened
|
|
#* - If an owner password is set, document can be opened in privilege mode with no
|
|
#* restriction if that password is entered
|
|
#*/
|
|
def SetProtection(this,permissions=[],user_pass='',owner_pass=None):
|
|
options={'print':4, 'modify':8, 'copy':16, 'annot-forms':32}
|
|
protection = 192
|
|
for permission in permissions:
|
|
if permission not in options:
|
|
this.Error('Incorrect permission: '+permission)
|
|
protection += options[permission]
|
|
|
|
if (owner_pass == None):
|
|
owner_pass=''
|
|
for i in range(13):
|
|
owner_pass += chr(random.randint(0,255))
|
|
this.encrypted = 1
|
|
this._generateencryptionkey(user_pass, owner_pass, protection)
|
|
|
|
|
|
#/****************************************************************************
|
|
#* *
|
|
#* Private methods *
|
|
#* *
|
|
#****************************************************************************/
|
|
def _putstream(this,s):
|
|
if (this.encrypted):
|
|
s = this._RC4(this._objectkey(this.n), s)
|
|
FPDF._putstream(this,s)
|
|
|
|
def _textstring(this,s):
|
|
if (this.encrypted):
|
|
s = this._RC4(this._objectkey(this.n), s)
|
|
return FPDF._textstring(this,s)
|
|
|
|
#/**
|
|
#* Compute key depending on object number where the encrypted data is stored
|
|
#*/
|
|
def _objectkey(this,n):
|
|
return substr(this._md5_16(this.encryption_key+struct.pack('L',n)[:-1]+'\x00\x00'),0,10)
|
|
|
|
#/**
|
|
#* Escape special characters
|
|
#*/
|
|
def _escape(this,s):
|
|
s=str_replace('\\','\\\\',s)
|
|
s=str_replace(')','\\)',s)
|
|
s=str_replace('(','\\(',s)
|
|
s=str_replace("\r",'\\r',s)
|
|
return s
|
|
|
|
def _putresources(this):
|
|
FPDF._putresources(this)
|
|
if (this.encrypted):
|
|
this._newobj()
|
|
this.enc_obj_id = this.n
|
|
this._out('<<')
|
|
this._putencryption()
|
|
this._out('>>')
|
|
this._out('endobj')
|
|
|
|
def _putencryption(this):
|
|
this._out('/Filter /Standard')
|
|
this._out('/V 1')
|
|
this._out('/R 2')
|
|
this._out('/O ('+this._escape(this.Ovalue)+')')
|
|
this._out('/U ('+this._escape(this.Uvalue)+')')
|
|
this._out('/P '+str(this.Pvalue))
|
|
|
|
def _puttrailer(this):
|
|
FPDF._puttrailer(this)
|
|
if (this.encrypted):
|
|
this._out('/Encrypt '+str(this.enc_obj_id)+' 0 R')
|
|
this._out('/ID [()()]')
|
|
|
|
#/**
|
|
#* RC4 is the standard encryption algorithm used in PDF format
|
|
#*/
|
|
def _RC4(this, key, text):
|
|
if (this.last_rc4_key != key):
|
|
k = str_repeat(key, 256/strlen(key)+1)
|
|
rc4 = array.array('B',range(256))
|
|
j = 0
|
|
for i in range(256):
|
|
t = rc4[i]
|
|
j = (j + t + ord(k[i])) % 256
|
|
rc4[i] = rc4[j]
|
|
rc4[j] = t
|
|
this.last_rc4_key = key
|
|
this.last_rc4_key_c = copy.copy(rc4)
|
|
else:
|
|
rc4 = copy.copy(this.last_rc4_key_c)
|
|
len = strlen(text)
|
|
a = 0
|
|
b = 0
|
|
out = ''
|
|
for i in range(len):
|
|
a = (a+1)%256
|
|
t= rc4[a]
|
|
b = (b+t)%256
|
|
rc4[a] = rc4[b]
|
|
rc4[b] = t
|
|
k = rc4[(rc4[a]+rc4[b])%256]
|
|
out+=chr(ord(text[i]) ^ k)
|
|
return out
|
|
|
|
#/**
|
|
#* Get MD5 as binary string
|
|
#*/
|
|
def _md5_16(this,string):
|
|
return md5.new(string).digest()
|
|
|
|
#/**
|
|
#* Compute O value
|
|
#*/
|
|
def _Ovalue(this, user_pass, owner_pass):
|
|
tmp = this._md5_16(owner_pass)
|
|
owner_RC4_key = substr(tmp,0,5)
|
|
return this._RC4(owner_RC4_key, user_pass)
|
|
|
|
#/**
|
|
#* Compute U value
|
|
#*/
|
|
def _Uvalue(this):
|
|
return this._RC4(this.encryption_key, this.padding)
|
|
|
|
#/**
|
|
#* Compute encryption key
|
|
#*/
|
|
def _generateencryptionkey(this, user_pass, owner_pass, protection):
|
|
# Pad passwords
|
|
user_pass = substr(user_pass+this.padding,0,32)
|
|
owner_pass = substr(owner_pass+this.padding,0,32)
|
|
# Compute O value
|
|
this.Ovalue = this._Ovalue(user_pass,owner_pass)
|
|
# Compute encyption key
|
|
tmp = this._md5_16(user_pass+this.Ovalue+chr(protection)+"\xFF\xFF\xFF")
|
|
this.encryption_key = substr(tmp,0,5)
|
|
# Compute U value
|
|
this.Uvalue = this._Uvalue()
|
|
# Compute P value
|
|
this.Pvalue = -((protection^255)+1)
|
|
|
|
if __name__ == '__main__':
|
|
pdf=Protection()
|
|
pdf.SetProtection(['print'])
|
|
pdf.Open()
|
|
pdf.AddPage()
|
|
pdf.SetFont('Arial')
|
|
pdf.Write(10,'You can print me but not copy my text.')
|
|
pdf.Output('Protected.pdf','F')
|