i want to write a hmac (hash-based message authentication code) in python. So far i managed to write the basic hmac but i want to add another parameter in the message. For example, message=(mac_address || index_value). Can somebody show me how to do it? And how can i save the output in another list (e.g. digest_hmac_list)?
from hashlib import shake_256
from zlib import crc32, adler32
class HMAC:
def __init__(self, key, message, hash_h=shake_256):
""" key and message must be byte object """
self.i_key_pad = bytearray()
self.o_key_pad = bytearray()
self.key = key
self.message = message
self.blocksize = 64
self.hash_h = hash_h
self.init_flag = False
def init_pads(self):
""" creating inner padding and outer padding """
for i in range(self.blocksize):
self.i_key_pad.append(0x36 ^ self.key[i])
self.o_key_pad.append(0x5c ^ self.key[i])
def init_key(self):
""" key regeneration """
if len(self.key) > self.blocksize:
self.key = bytearray(shake_256(key).digest())
elif len(self.key) < self.blocksize:
i = len(self.key)
while i < self.blocksize:
self.key += b"\x00"
i += 1
def digest(self):
if self.hash_h == adler32 or self.hash_h == crc32:
return self.hash_h(bytes(self.o_key_pad)+str(self.hash_h(bytes(self.i_key_pad)+self.message)).encode())
""" returns a digest, byte object. """
""" check if init_flag is set """
if self.init_flag == False:
self.init_key()
self.init_pads()
""" hold init_flag for good. """
self.init_flag = True
return self.hash_h(bytes(self.o_key_pad)+self.hash_h(bytes(self.i_key_pad)+self.message).digest()).digest()
def hexdigest(self):
if self.hash_h == adler32 or self.hash_h == crc32:
return hex(self.hash_h(bytes(self.o_key_pad)+str(self.hash_h(bytes(self.i_key_pad)+self.message)).encode()))[2:]
""" returns a digest in hexadecimal. """
""" check if init_flag is set """
if self.init_flag == False:
""" init key and padding. """
self.init_key()
self.init_pads()
""" set init_flag for good. """
self.init_flag = True
I fixed some small issues in Your code and made it so you can hash 2 different (mac || index) with same key and save it in a self.digest_all_list. I commented out all these things in the code.
from hashlib import shake_256
from zlib import crc32, adler32
class HMAC:
def __init__(self, key, message, hash_h=shake_256):
""" key and message must be byte object """
self.i_key_pad = bytearray()
self.o_key_pad = bytearray()
self.key = key
self.message = message
self.blocksize = 64
self.hash_h = hash_h
self.init_flag = False
# This will contain all hashed messages
self.digest_hmac_list = []
def init_pads(self):
""" creating inner padding and outer padding """
for i in range(self.blocksize):
self.i_key_pad.append(0x36 ^ self.key[i])
self.o_key_pad.append(0x5c ^ self.key[i])
def init_key(self):
""" key regeneration """
if len(self.key) > self.blocksize:
self.key = bytearray(shake_256(self.key).digest(self.blocksize))
elif len(self.key) < self.blocksize:
i = len(self.key)
while i < self.blocksize:
self.key += b"\x00"
i += 1
def digest(self, message = None):
# If you want to Hash 2 different message with same key(so same class instance)
# pass message to digest and default to self.message
if message:
self.message = bytearray(message, encoding="ascii")
if self.hash_h == adler32 or self.hash_h == crc32:
return self.hash_h(bytes(self.o_key_pad)+str(self.hash_h(bytes(self.i_key_pad)+self.message)).encode())
""" returns a digest, byte object. """
""" check if init_flag is set """
if self.init_flag == False:
self.init_key()
self.init_pads()
""" hold init_flag for good. """
self.init_flag = True
# You Forget to specify the size of the Hash shake_256 allow for arbitrary output(Not like SHA-2)
# , I chosen 64 byte you can you chose whatever you want
self.digest_hmac_list.append(self.hash_h(bytes(self.o_key_pad) + self.hash_h(bytes(self.i_key_pad) + self.message).digest(self.blocksize)).digest(self.blocksize))
return self.digest_hmac_list[-1]
def hexdigest(self, message = None):
# If you want to Hash 2 different message with same key(so same class instance)
# pass message to digest and default to self.message
if message:
self.message = bytearray(message, encoding="ascii")
# Checking must be Done First So you can initialize all required parts then hash the message
""" check if init_flag is set """
if self.init_flag == False:
""" init key and padding. """
self.init_key()
self.init_pads()
""" set init_flag for good. """
self.init_flag = True
if self.hash_h == adler32 or self.hash_h == crc32:
self.digest_hmac_list.append(hex(self.hash_h(bytes(self.o_key_pad) + str(self.hash_h(bytes(self.i_key_pad) + self.message)).encode())[2:]))
return self.digest_hmac_list[-1]
""" returns a digest in hexadecimal. """
# NOTE: You are Not hashing anything if the default Hash function is shake_256, add
# code here to add hexHashing for default
# message is mac then post pended with Index if that what I understand
index = "0"
mac = "FF0A8CD1DAAB"
key = "This is key"
cl = HMAC(bytearray(key, encoding="ascii"), bytearray(mac + index, encoding="ascii"), shake_256)
print(cl.digest())
print("=="*10)
index = "1"
print(cl.digest(mac + index))
print("=="*10)
print(cl.digest_hmac_list)
Related
I am trying to write a state machine whose inputs are the characters of a string (representing a
Python program) and which outputs either (a) the input character if it is part of a
comment or (b) None
but so far I have failed
I got the error TypeError: cannot unpack non-iterable NoneType object
def split(word):
return [char for char in word]
class SM:
def start(self):
self.state = self.startState
def sit(self,inp):
(s,o) = self.comments(inp,self.state)
self.state = s
return o
def transduce(self,input):
self.start()
return [self.sit(inp) for inp in input]
class commentSM(SM):
startState = ''
def showcom(self,list,val):
for char in list:
if list.find(char) < list.find(val):
return None
else:
return char
def comments(self,input,state):
if state == '':
return('commented',self.showcom(input,'#'))
input = '''print(hello) # comment'''
ninput = split(input)
m = commentSM()
print(m.transduce(ninput))
After having implemented Huffman coding for text in Python, how do I effectively encrypt the resultant Huffman codes in AES-128? Huffman Coding using Python
For example, "Spiderman is Peter Parker" becomes 0000100000001111110110101110001011011000011110010000010111011011010100000100100101010011010 after Huffman encoding.
How do I encrypt these bits using AES?
# Node of a Huffman Tree
class Nodes:
def __init__(self, probability, symbol, left = None, right = None):
# probability of the symbol
self.probability = probability
# the symbol
self.symbol = symbol
# the left node
self.left = left
# the right node
self.right = right
# the tree direction (0 or 1)
self.code = ''
""" A supporting function in order to calculate the probabilities of symbols in specified data """
def CalculateProbability(the_data):
the_symbols = dict()
for item in the_data:
if the_symbols.get(item) == None:
the_symbols[item] = 1
else:
the_symbols[item] += 1
return the_symbols
""" A supporting function in order to print the codes of symbols by travelling a Huffman Tree """
the_codes = dict()
def CalculateCodes(node, value = ''):
# a huffman code for current node
newValue = value + str(node.code)
if(node.left):
CalculateCodes(node.left, newValue)
if(node.right):
CalculateCodes(node.right, newValue)
if(not node.left and not node.right):
the_codes[node.symbol] = newValue
return the_codes
""" A supporting function in order to get the encoded result """
def OutputEncoded(the_data, coding):
encodingOutput = []
for element in the_data:
# print(coding[element], end = '')
encodingOutput.append(coding[element])
the_string = ''.join([str(item) for item in encodingOutput])
return the_string
""" A supporting function in order to calculate the space difference between compressed and non compressed data"""
def TotalGain(the_data, coding):
# total bit space to store the data before compression
beforeCompression = len(the_data) * 8
afterCompression = 0
the_symbols = coding.keys()
for symbol in the_symbols:
the_count = the_data.count(symbol)
# calculating how many bit is required for that symbol in total
afterCompression += the_count * len(coding[symbol])
print("Space usage before compression (in bits):", beforeCompression)
print("Space usage after compression (in bits):", afterCompression)
def HuffmanEncoding(the_data):
symbolWithProbs = CalculateProbability(the_data)
the_symbols = symbolWithProbs.keys()
the_probabilities = symbolWithProbs.values()
print("symbols: ", the_symbols)
print("probabilities: ", the_probabilities)
the_nodes = []
# converting symbols and probabilities into huffman tree nodes
for symbol in the_symbols:
the_nodes.append(Nodes(symbolWithProbs.get(symbol), symbol))
while len(the_nodes) > 1:
# sorting all the nodes in ascending order based on their probability
the_nodes = sorted(the_nodes, key = lambda x: x.probability)
# for node in nodes:
# print(node.symbol, node.prob)
# picking two smallest nodes
right = the_nodes[0]
left = the_nodes[1]
left.code = 0
right.code = 1
# combining the 2 smallest nodes to create new node
newNode = Nodes(left.probability + right.probability, left.symbol + right.symbol, left, right)
the_nodes.remove(left)
the_nodes.remove(right)
the_nodes.append(newNode)
huffmanEncoding = CalculateCodes(the_nodes[0])
print("symbols with codes", huffmanEncoding)
TotalGain(the_data, huffmanEncoding)
encodedOutput = OutputEncoded(the_data,huffmanEncoding)
return encodedOutput, the_nodes[0]
def HuffmanDecoding(encodedData, huffmanTree):
treeHead = huffmanTree
decodedOutput = []
for x in encodedData:
if x == '1':
huffmanTree = huffmanTree.right
elif x == '0':
huffmanTree = huffmanTree.left
try:
if huffmanTree.left.symbol == None and huffmanTree.right.symbol == None:
pass
except AttributeError:
decodedOutput.append(huffmanTree.symbol)
huffmanTree = treeHead
string = ''.join([str(item) for item in decodedOutput])
return string
the_data = "Spiderman is Peter Parker"
print(the_data)
encoding, the_tree = HuffmanEncoding(the_data)
print("Encoded output", encoding)
print("Decoded Output", HuffmanDecoding(encoding, the_tree))
Many packages support AES encryption, one of which is PyCryptodome.
For example, to encrypt using EAX mode:
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
data = bytes(encoding, 'utf-8')
key = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_EAX)
ciphertext, tag = cipher.encrypt_and_digest(data)
I'm given a .txt file with a total of 1 million songs and their respective authors. My given task is to write a HashMap in python which can store this information using either the Author or the Song as a key. I've written a HashMap that works but is running incredibly slow, taking up to 2 minutes to finish. (Expected time is apparently a few seconds at most, according to my tutor)
For collision handling I decided to use linked lists as from what I've gathered it's an effective way to handle collisions without drastically reducing performance.
from HashNode import HashNode
class HashTabell:
def __init__(self, size):
self.size = size
self.dict = {}
self.krock = 0
def store(self, nyckel, data):
hashval = self.__hash(nyckel)
## Shit is empty
if self.dict.get(hashval) != None:
get_val = self.dict[hashval]
## Is list, append normally
if isinstance(get_val, list):
list2 = self.dict[hashval]
found = False
for (k, val) in enumerate(list2):
if val.get_nyckel == nyckel:
list[k] = HashNode(nyckel, data) ## Update old value
found = True
break
if found:
self.dict[hashval] = list2
else:
self.dict[hashval] = get_val + [HashNode(nyckel, data)]
self.krock += 1
else:
## Create list
if get_val.get_nyckel() == nyckel:
self.dict[hashval] = HashNode(nyckel, data) ## Update old value
else:
self.dict[hashval] = [get_val, HashNode(nyckel, data)] ## Append to existing node
self.krock += 1
else:
self.dict[hashval] = HashNode(nyckel, data)
def __getitem__(self, nyckel):
return search(nyckel)
def __contains__(self, nyckel):
return (search(nyckel) != None)
def search(self, nyckel):
hashval = self.__hash(nyckel)
## Get val
get_val = self.dict.get(hashval)
if get_val == None:
raise KeyError("Key not found")
## Check if has multiple entries or not
if isinstance(get_val, list):
## Multiple
for value in get_val:
if(get_val.get_nyckel() == nyckel):
return get_val
raise KeyError("Key not found")
else:
## Single
if get_val.get_nyckel() == nyckel:
return get_val
else:
raise KeyError("Key not found")
## Hash function
def __hash(self, input):
inp = str(input) ## Get chars
value = 0
for k in input:
value += ord(k)
return (value % self.size)
def get_dict(self):
return self.dict
def get_krock(self):
return self.krock
Where the HashNode class is simply:
class HashNode:
def __init__(self, nyckel, data):
self.nyckel = nyckel
self.data = data
def get_nyckel(self):
return self.nyckel
def get_data(self):
return self.data
I've been staring myself blind with this issue for the past 2 weeks and I'm not getting any help from my lecturer/assistants, would greatly appreciate any advice on how to improve the speed.
I'm trying to implement CTR mode by myself (only decryption for now), using only AES built-in functions from pycrypto. It means that I'm not supposed to use mode=AES.MODE_CTR. However, I know that using AES.MODE_CTR would be more simple, but I'm doing this as a learning experience.
I'm not sure about how to use AES as a PRF, in order to use it in a CTR cryptography algorithm.
What am I doing wrong?
(non-parallalel version)
from Crypto.Cipher import AES
ciphers = ["69dda8455c7dd4254bf353b773304eec0ec7702330098ce7f7520d1cbbb20fc3" + \
"88d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329", \
"770b80259ec33beb2561358a9f2dc617e46218c0a53cbeca695ae45faa8952aa" + \
"0e311bde9d4e01726d3184c34451"]
key = "36f18357be4dbd77f050515c73fcf9f2"
class IVCounter(object):
def __init__(self, value):
self.value = value
def increment(self):
# Add the counter value to IV
newIV = hex(int(self.value.encode('hex'), 16) + 1)
# Cut the negligible part of the string
self.value = newIV[2:len(newIV) - 1].decode('hex') # for not L strings remove $ - 1 $
return self.value
def __repr__(self):
self.increment()
return self.value
def string(self):
return self.value
class CTR():
def __init__(self, k):
self.key = k
def __strxor(self, a, b): # xor two strings of different lengths
if len(a) > len(b):
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
else:
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])
def __split_len(self, seq, lenght):
return [seq[i:i+lenght] for i in range(0, len(seq), lenght)]
def __AESdecryptor(self, k, cipher):
decryptor = AES.new(k, AES.MODE_ECB)
return decryptor.decrypt(cipher)
def decrypt(self, cipher):
# Split the CT in blocks of 16 bytes
blocks = self.__split_len(cipher.decode('hex'), 16)
# Takes the initiator vector
self.IV = IVCounter(blocks[0])
blocks.remove(blocks[0])
# Message block
msg = []
# Decrypt
for b in blocks:
aes = self.__AESdecryptor(self.key.decode('hex'), self.IV.string())
msg.append(self.__strxor(b, aes))
self.IV.increment()
return ''.join(msg)
def main():
decryptor = CTR(key)
for c in ciphers:
print 'msg = ' + decryptor.decrypt(c)
if __name__ == '__main__':
main()
This code was supposed to do the same that the code below, but it is not decoding as it should be.
import Crypto.Util.Counter
ctr_e = Crypto.Util.Counter.new(128, initial_value=long(IV.encode('hex'), 16))
decryptor = AES.new(key.decode('hex'), AES.MODE_CTR, counter=ctr_e)
print decryptor.decrypt(''.join(blocks))
# Decrypt
for b in blocks:
aes = self.__AESdecryptor(self.IV.string(), self.key.decode('hex'))
msg.append(self.__strxor(b, aes))
self.IV.increment()
return ''.join(msg)
AES CTR mode uses AES's forward transformation for both encryption and decryption. That is, in both cases, encrypt the counter and then perform the XOR. When I say the 'forward transformation', I mean you always perform AES_Encrypt(counter) (and never perform AES_Decrypt(counter)).
You perform the XOR on both the plain text and the cipher text, irregardless of whether you are encrypting or decrypting. text XOR encrypt(counter) is the encryption or decryption operation. That's a stream cipher.
self.IV.string() is not the AES key. Its the value that is encrypted under the key. Once encrypted, it is XOR'd with the {plain|cipher} text.
I've finally got this code working well, and the mistake was very simple. I shouldn't have used decrypt AES function, I should have used encrypt AES function (as noloader had said, and I'd not understood him very well at the first time). Thanks for everybody who helped and here is the fixed code:
from Crypto.Cipher import AES
ciphers = ["69dda8455c7dd4254bf353b773304eec0ec7702330098ce7f7520d1cbbb20fc3" + \
"88d1b0adb5054dbd7370849dbf0b88d393f252e764f1f5f7ad97ef79d59ce29f5f51eeca32eabedd9afa9329", \
"770b80259ec33beb2561358a9f2dc617e46218c0a53cbeca695ae45faa8952aa" + \
"0e311bde9d4e01726d3184c34451"]
key = "36f18357be4dbd77f050515c73fcf9f2"
class IVCounter(object):
def __init__(self, value):
self.value = value
def increment(self):
# Add the counter value to IV
newIV = hex(int(self.value.encode('hex'), 16) + 1)
# Cut the negligible part of the string
self.value = newIV[2:len(newIV) - 1].decode('hex') # for not L strings remove $ - 1 $
return self.value
def __repr__(self):
self.increment()
return self.value
def string(self):
return self.value
class CTR():
def __init__(self, k):
self.key = k.decode('hex')
def __strxor(self, a, b): # xor two strings of different lengths
if len(a) > len(b):
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a[:len(b)], b)])
else:
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b[:len(a)])])
def __split_len(self, seq, lenght):
return [seq[i:i+lenght] for i in range(0, len(seq), lenght)]
def __AESencryptor(self, cipher):
encryptor = AES.new(self.key, AES.MODE_ECB)
return encryptor.encrypt(cipher)
def decrypt(self, cipher):
# Split the CT into blocks of 16 bytes
blocks = self.__split_len(cipher.decode('hex'), 16)
# Takes the initiator vector
self.IV = IVCounter(blocks[0])
blocks.remove(blocks[0])
# Message block
msg = []
# Decrypt
for b in blocks:
aes = self.__AESencryptor(self.IV.string())
msg.append(self.__strxor(b, aes))
self.IV.increment()
return ''.join(msg)
def main():
decryptor = CTR(key)
for c in ciphers:
print 'msg = ' + decryptor.decrypt(c)
if __name__ == '__main__':
main()
I want to compress my movies automatically. So I've written a mediainfo wrapper class in python, to generate a xml output, which I then parse to a movieinfo class, with a list of audio and subtitle tracks.
__author__ = 'dominik'
class Error(Exception):
""" Error class
"""
class ValidationError(Error):
""" Invalid or missing xml items
"""
class MovieInfo(object):
""" Description of movie file
"""
def __init__(self, media_info):
self._video_track = None
self._audio_tracks = []
self._subtitle_tracks = []
self.valid_movie = True
for track in media_info.tracks:
if track.track_type == "Audio":
self._audio_tracks.append(AudioTrack(track))
elif track.track_type == "Text":
self._subtitle_tracks.append(SubtitleTrack(track))
elif track.track_type == "Video":
self._video_track = VideoTrack(track)
#property
def audio_tracks(self):
if not hasattr(self, "_audio_tracks"):
self._audio_tracks = []
if len(self._audio_tracks) != 0:
return self._audio_tracks
#property
def subtitle_tracks(self):
if not hasattr(self, "_subtitle_tracks"):
self._subtitle_tracks = []
if len(self._subtitle_tracks) != 0:
return self._subtitle_tracks
class Track(object):
""" Abstract track class for audio and subtitle tracks
"""
__KNOWN_LANGUAGE_CODES = {"en": "ENG", "de": "DE"}
def __init__(self, track, valid_codecs):
self._valid = True
track_id = int(track.id)
codec_id = self._determine_codec(track.codec_id, valid_codecs)
language = self._determine_language(track.language)
self._id = track_id
self._codec_id = codec_id
self._language = language
def _determine_codec(self, track_codec, types):
result = types.get(track_codec, None)
if result is None:
self._valid = False
return result
def _determine_language(self, track_language, types=__KNOWN_LANGUAGE_CODES):
result = types.get(track_language, None)
if result is None:
self._valid = False
return result
class AudioTrack(Track):
""" Audio track class
"""
__KNOWN_AUDIO_CODECS = {"A_DTS": "DTS", "A_AC3": "AC3"}
def __init__(self, track):
self._type = 1
Track.__init__(self, track, self.__KNOWN_AUDIO_CODECS)
class SubtitleTrack(Track):
""" Subtitle track class
"""
__KNOWN_SUBTITLE_CODECS = {"S_VOBSUB": "VOBSUB"}
def __init__(self, track):
self._type = 2
if track.forced == "Yes":
self._forced = True
else:
self._forced = False
Track.__init__(self, track, self.__KNOWN_SUBTITLE_CODECS)
class VideoTrack(object):
""" Video track class (only one video track in movie info!)
"""
def __init__(self, track):
self._type = 0
self._framerate = float(track.frame_rate)
self._width = track.width
self._height = track.height
Here is the mediainfo class (it's the pymediainfo class):
from subprocess import Popen
import os
from tempfile import mkstemp
from bs4 import BeautifulSoup, NavigableString
from setuptools.compat import unicode
class Track(object):
""" Hold the track information
"""
def __getattr__(self, item):
try:
return object.__getattribute__(self, item)
except:
pass
return None
def __init__(self, xml_track):
self.xml_track = xml_track
self.track_type = xml_track.attrs["type"]
for child in self.xml_track.children:
if not isinstance(child, NavigableString):
node_name = child.name.lower().strip()
node_value = unicode(child.string)
node_other_name = "other_%s" % node_name
if getattr(self, node_name) is None:
setattr(self, node_name, node_value)
else:
if getattr(self, node_other_name) is None:
setattr(self, node_other_name, [node_value, ])
else:
getattr(self, node_other_name).append(node_value)
for key in [c for c in self.__dict__.keys() if c.startswith("other_")]:
try:
primary = key.replace("other_", "")
setattr(self, primary, int(getattr(self, primary)))
except:
for value in getattr(self, key):
try:
actual = getattr(self, primary)
setattr(self, primary, int(value))
getattr(self, key).append(actual)
break
except:
pass
def __repr__(self):
return("<Track id='{0}', type='{1}'>".format(self.id, self.track_type))
def to_data(self):
data = {}
for k, v in self.__dict__.items():
if k != 'xml_track':
data[k] = v
return data
class Mediainfo(object):
""" MediaInfo wrapper
"""
def __init__(self, xml):
self.xml_dom = xml
if isinstance(xml, str):
self.xml_dom = BeautifulSoup(xml, "xml")
def _populate_tracks(self):
if self.xml_dom is None:
return
for xml_track in self.xml_dom.Mediainfo.File.find_all("track"):
self._tracks.append(Track(xml_track))
#property
def tracks(self):
if not hasattr(self, "_tracks"):
self._tracks = []
if len(self._tracks) == 0:
self._populate_tracks()
return self._tracks
#staticmethod
def parse(filename):
filehandler_out, filename_out = mkstemp(".xml", "mediainfo-")
filehandler_err, filename_err = mkstemp(".error", "mediainfo-")
filepointer_out = os.fdopen(filehandler_out, "r+b")
filepointer_err = os.fdopen(filehandler_err, "r+b")
mediainfo_command = ["mediainfo", "-f", "--Output=XML", filename]
p = Popen(mediainfo_command, stdout=filepointer_out, stderr=filepointer_err)
p.wait()
filepointer_out.seek(0)
xml_dom = BeautifulSoup(filepointer_out.read(), "xml")
filepointer_out.close()
filepointer_err.close()
print(xml_dom)
return Mediainfo(xml_dom)
def to_data(self):
data = {'tracks': []}
for track in self.tracks:
data['tracks'].append(track.to_data())
return data
This class gives me every track in the xml and then I parse the relevant info in movieinfo.
Ok now I have a list of audiotracks e.g. 3 tracks one in german language and DTS, one in german and AC3 and one in english and AC3. Now I want to get the ids from the tracks in the format "1,2,3" to give it to handbrake cli.
My problem is the order of the tracks. If there is a german DTS track this schould be the first track, the second track should be also the first, but compressed to aac and the third track should be one english track in AAC. If there is only a german AC3 track then the first track should be this track but compressed to AAC, and the second track should englisch and AAC.
I don't know exactly how I can achive that, can you help me? I'm new to python, and come from C, C++ and C#. In C# this is very easy to get with lambda.
Assuming you know to define a compare-tor that given two items can define which is bigger then Python functions as well as C or C++.
Start here -
1. https://wiki.python.org/moin/HowTo/Sorting/
https://developers.google.com/edu/python/sorting
http://docs.python.org/2/library/functions.html#sorted
Using sorted method and define the key you want.