Die EasyBox von Arcor/Vodafon sichert die Konfiguration verschlüßelt ab. Im Internet findet man Java Code um die Datei zu entschlüsseln, z.B. hier: http://www.arcor-user-forum.de/sprachpa ... hode-4550/
Der Ursprüngliche code stammt wohl von http://wiki.openwrt.org/toh/arcadyan/arv7506 und linkt auf http://pastebin.com/AR4t75HR
Der JavaCode ist nicht lang. Doch Java kenne ich so garnicht.
Weiß jemand wie man das in Python übersetzt? Bzw. hat jemand Lust das in Python zu implementieren ?
Java -> Python: Arcor/Vodafon DLS Box config decodieren...
@jens: Der Java-Quelltext selbst sollte relativ einfach zumindest in „unpythonisches” Python übersetzbar sein. So beim kurzen drüber schauen und fast eben so kurzer Recherche im Netz dürfte die AES-Verschlüsselung das Problem sein, oder genauer der Modus CTS. Da habe ich nichts für Python gefunden. Die Bibliotheken können zwar alle 'CBC', 'CFB', 'OFB', und 'ECB', aber 'CTS' scheint eher exotisch zu sein.
Mal so als Anfang die `BytePairDecompressionStream`-Klasse von einer Push-API in eine Pull-API als Generatorfunktion umgeschrieben:
Die Funktion erwartet ein iterierbares Objekt über Zeichen (also zum Beispiel eine Zeichenkette) und liefert ebenfalls Zeichen.
Mal so als Anfang die `BytePairDecompressionStream`-Klasse von einer Push-API in eine Pull-API als Generatorfunktion umgeschrieben:
Code: Alles auswählen
def byte_pair_decompress(bytes):
bytes = iter(bytes)
escape_value = bytes.next()
entry_count = ord(bytes.next())
pair_expansion = dict(
(bytes.next(), (bytes.next(), bytes.next())
for _ in xrange(entry_count)
)
if bytes.next() != '\x5b':
raise ValueError('Bad magic after map')
for value in bytes:
if value == escape_value:
yield bytes.next()
else:
for value in pair_expansion.get(value, [value]):
yield value
@jens: Wofür brauchst Du das in Python? Verwende doch einfach das Java-Programm, wenn es gut funktioniert…
Die Implementierung in Python wird ohnehin schwierig, nicht weil Python per se ungeeignet wäre, sondern weil es keine vernünftige Bibliothek für kryptographische Funktionen gibt.
Die Implementierung in Python wird ohnehin schwierig, nicht weil Python per se ungeeignet wäre, sondern weil es keine vernünftige Bibliothek für kryptographische Funktionen gibt.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
In Python selbst konnte ich auch nichts finden. Bin mal die Liste der Implementierungen bei https://en.wikipedia.org/wiki/AES_imple ... ons#Python durchgegangen und nach CTS gesucht und nichts gefunden.
Beschrieben ist RC5-CTS wohl in RFC 2040: https://tools.ietf.org/html/rfc2040
Wie CFB, OFB und CBC funktioniert kann man z.B. bei https://code.google.com/p/slowaes/sourc ... aes.py#450 sehen... Ob CTS komplizierter ist?
Man kann mit Jython arbeiten, z.B.: https://code.google.com/p/8-bits/source ... ecrypto.py
Allerdings kann ich dann genauso gut direkt das original Java Programm nehmen.
@lunar: Klar kann ich auch die Java Implementierung nehmen. Hab ich auch gemacht. Nur interessehalber möchte ich gern das selbe in Python sehen. Schade das es nicht so einfach ist...
Beschrieben ist RC5-CTS wohl in RFC 2040: https://tools.ietf.org/html/rfc2040
Wie CFB, OFB und CBC funktioniert kann man z.B. bei https://code.google.com/p/slowaes/sourc ... aes.py#450 sehen... Ob CTS komplizierter ist?
Man kann mit Jython arbeiten, z.B.: https://code.google.com/p/8-bits/source ... ecrypto.py
Code: Alles auswählen
from javax.crypto import Cipher
cipher = Cipher.getInstance("AES/CTS/NoPadding")
@lunar: Klar kann ich auch die Java Implementierung nehmen. Hab ich auch gemacht. Nur interessehalber möchte ich gern das selbe in Python sehen. Schade das es nicht so einfach ist...
@jens: Das wäre dann ein idealer Zeitpunkt, um Java zu lernen, und sich in Kryptographie einzuarbeiten… 

- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Das ist so ähnlich wie beim Kinderkriegen... den idealen Zeitpunkt gibt es nie - aber mal im Ernst: Es gibt wirklich schlimmeres als Java!EyDu hat geschrieben: Es gibt einen guten Zeitpunkt um Java zu lernen?!

encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@lunar: Warum sind die vorhandenen Bibliotheken nicht vernünftig? Ich habe auf Anhieb vier gefunden die offensichtlich die „normalen” Modi ('CBC', 'CFB', 'OFB', und 'ECB') und AES können. PyCrypto, m2crypto, ncrypt, und pycryptopp. Nur halt CTS nicht.
@jens: Zu CTS gibt es einen englischsprachigen Wikipedia-Eintrag wo erklärt wird, wie sich das von anderen Modi unterscheidet. Sieht so aus, als könnte man auf bestimmten anderen Aufbauen und müsste nur die letzten beiden Blöcke besonders behandeln. Das ist dazu da um bei einem Block-Cipher ohne explizites Padding der Ausgangsdaten aus zu kommen. Dazu werden Daten aus dem vorletzen Block genommen um den letzten aufzufüllen. Falls ich das richtig verstanden habe.
Wenn ich keinen Fehler gemacht habe, und Du eine Crypto-Bibliothek findest, die AES im CTS-Modus kann, dann müsste das ungefähr so aussehen:
@jens: Zu CTS gibt es einen englischsprachigen Wikipedia-Eintrag wo erklärt wird, wie sich das von anderen Modi unterscheidet. Sieht so aus, als könnte man auf bestimmten anderen Aufbauen und müsste nur die letzten beiden Blöcke besonders behandeln. Das ist dazu da um bei einem Block-Cipher ohne explizites Padding der Ausgangsdaten aus zu kommen. Dazu werden Daten aus dem vorletzen Block genommen um den letzten aufzufüllen. Falls ich das richtig verstanden habe.
Wenn ich keinen Fehler gemacht habe, und Du eine Crypto-Bibliothek findest, die AES im CTS-Modus kann, dann müsste das ungefähr so aussehen:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from hashlib import md5
from struct import Struct
from Crypto.Cipher import AES
KEYS = [
'\x1d\xe5\xfa\xb8\x81\x91\x00\x84\x11\xaf\x53\xdd\xe4\x89\xea\xfd',
'\xa9\xdc\x0e\xf0\x28\x67\x91\xac\xc9\x13\x86\x5d\x2d\xf8\x20\x99',
'\x1a\xa8\x80\xb5\x44\x11\xf1\x19\x0c\xca\x3d\xe8\x77\x41\x37\x89',
'\x45\x68\x70\x98\x7a\xcd\xeb\xbb\xbd\xed\xa8\x03\x98\x73\x40\x24',
]
HEADER_STRUCT = Struct('<iib16s')
HEADER_SIZE = 0x28
PAYLOAD_HEADER_STRUCT = Struct('<HBBH')
def byte_pair_decompress(bytes):
escape_value = bytes.next()
entry_count = ord(bytes.next())
pair_expansion = dict(
(bytes.next(), (bytes.next(), bytes.next()))
for _ in xrange(entry_count)
)
if bytes.next() != '\x5b':
raise ValueError('Bad magic after map')
for value in bytes:
if value == escape_value:
yield bytes.next()
else:
for value in pair_expansion.get(value, [value]):
yield value
def unpack_header(data, expected_magic, check_key_number=True):
magic, size, key_number, expected_md5 = HEADER_STRUCT.unpack(
data[:HEADER_STRUCT.size]
)
if magic != expected_magic:
raise ValueError('Bad magic')
if check_key_number:
if not (0 <= key_number < len(KEYS)):
raise ValueError('Bad key number (0-%d expected)' % len(KEYS) - 1)
return size, key_number, expected_md5
def extract_config(in_file=sys.stdin, out_file=sys.stdout):
init_vector = in_file.read(16)
cipher = AES.new(KEYS[0], AES.MODE_CBC, init_vector) # BUG Mode is incorrect.
header = cipher.decrypt(in_file.read(HEADER_SIZE))
size, key_number, expected_md5 = unpack_header(header, 0x59585756)
body = in_file.read(size)
if expected_md5 != md5(body).digest():
raise ValueError('Body MD5 does not match')
cipher = AES.new(KEYS[key_number], AES.MODE_CBC, body[:16]) # BUG See above.
payload = cipher.decode(body[16:])
size, _key_number, expected_md5 = unpack_header(payload, 0x48464442, False)
if expected_md5 != md5(payload[HEADER_SIZE:]).digest():
raise ValueError('Payload MD5 does not match')
data_offset = HEADER_SIZE + PAYLOAD_HEADER_STRUCT.size
magic, levels, size_high, size_low = PAYLOAD_HEADER_STRUCT.unpack(
payload[HEADER_SIZE:data_offset]
)
if magic != 0x6562:
raise ValueError('Byte-pair compression magic does not match')
compressed_size = size_high << 16 | size_low
bytes = payload[data_offset:compressed_size]
for _ in xrange(levels):
bytes = byte_pair_decompress(bytes)
out_file.writelines(bytes)
def main():
extract_config()
if __name__ == '__main__':
main()
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
@BlackJack: Wow, danke dafür...
Leider funktioniert das auf anhieb nicht:
HEADER_SIZE ist wie im original = 0x28 also == 40 und somit nicht durch 16 teilbar.
Leider funktioniert das auf anhieb nicht:
Code: Alles auswählen
header = cipher.decrypt(in_file.read(HEADER_SIZE))
ValueError: Input strings must be a multiple of 16 in length
@jens: Ja natürlich funktioniert das nicht. Das habe ich doch geschrieben, dafür wäre der CTS-Modus da um aus einem Block-Cipher einen zu machen der auch Daten verarbeiten kann die nicht ein Vielfaches der Blockgrösse gross sind. Das sind die beiden Stellen im Quelltext wo der BUG-Kommentar steht.
@BlackJack: BouncyCastle ist das Maß aller Dinge, was Kryptographie angeht, und nur m2crypto kann damit annähernd mithalten, aber eben nur annähernd, wie diese Diskussion zeigt. PyCrypto und pycyptopp unterstützen nur Algorithmen, keine Protokolle wie S/MIME oder OpenPGP, ja nicht einmal Padding-Modi für Blockchiffren, oder Funktionen zur Schlüsselerzeugung wie PBKDF2. Von der ziemlich unterirdischen Dokumentation dieser Bibliotheken ganz zu schweigen…
Zu ncrypt habe ich keine näheren Informationen außer der Seite im Cheeseshop finden können.
Zu ncrypt habe ich keine näheren Informationen außer der Seite im Cheeseshop finden können.