Vector Verschlüsselung

Ich will erst mal eine einfache (symmetrische) Verschlüsselung machen.

class Vector(object):
    def __init__(self, length, values = []):
        if(length % 4):
            raise ValueError("Length has to be a multiple of 8")
        self._value = [None for i in range(length)]
        self._lock = [False for i in range(length)]
        self._length = length
        for pos, val in enumerate(values):
            self[pos] = val

    def __setitem__(self, iter_, item):
        if(not isinstance(item, int)):
            raise ValueError("Vector does not support {} items".format(type(item)))
        if(not isinstance(iter_, int)):
            raise ValueError("Vector indices have to be int, not {}".format(type(iter_)))
        if(iter_ >= self._length or iter_ < 0):
            raise IndexError("{} out of {}".format(iter_, range(self._length)))

        if(self._lock[iter_]):
            raise IndexError("Index {} already locked".format(iter_))
        self._value[iter_] = item
        self._lock[iter_] = True
    def __getitem__(self, iter_):
        if(isinstance(iter_, int)):
            if(not iter_ in range(self._length)):
                raise IndexError("Index {} out of {}".format(iter_, range(self._length)))
            return self._value[iter_]
        if(isinstance(iter_, slice)):
            try:
               return self._value[iter_]
            except:
                pass
            raise IndexError("Slice {} out of {}".format(iter_, range(self._length)))

        raise ValueError("Vector indices have to be int or slice, not {}".format(type(iter_)))
    def __str__(self):
        return "<Vector>({})".format(self._value)
    def __repr__(self):
        return "Vector({}, values = {})".format(self._length, repr(self._value))
    def __len__(self):
        return self._length


    def __mul__(self, other):
        if(isinstance(other, int)):
            return Vector(self._length, values = [v * other for v in self._value])
        raise ValueError("Cannot __mul__ Vector and {}".format(type(other)))
    def __matmul__(self, other):
        if(isinstance(other, Vector)):
            return sum([ v1 * v2 for v1, v2 in zip(other._value, self._value)])
        raise ValueError("Cannor __matmul__ Vector and {}".format(type(other)))
    def _rmatmul__(self, other):
        return self.__matmul__(other)

    def __rmul__(self, other):
        return self.__mul__(other)

    def bytes_to_vectors(self, bytes_):
        numbytes = len(bytes_)
        numvectors = numbytes // (self._length // 8)
        for vect in range(numvectors):
            yield self.bytes_to_vector(bytes_)
            bytes_ = bytes_[self._length // 8:]
        if(len(bytes_) != 0):
            yield self.bytes_to_vector(bytes_)

    def bytes_to_vector(self, bytes_):
        if(len(bytes_) < self._length // 8):
            bytes_ = bytes_ + b"\x00" * ((self._length // 8) - len(bytes_))
        vect = Vector(self._length)
        for bytepos, byte in enumerate(bytes_[:self._length // 8]):
            for shift in range(8):
                vect[bytepos * 8 + shift] = ((byte & (1 << shift)) >> shift)
        return vect

Das ist schonmal die erste Vectorimplementierung. (__matmul__ geht ab 3.5.2)

Einen ersten Verschlüsselungsvector kann man ganz leicht erzeugen.

Für einen Verschlüsselungsvector gilt:

v[k] > sum(v[:k])

Also kann man einen Vektor mit Zufallselementen so erzeugen:

v[k] = v[k - 1] * 2 + r
für alle k > 0; r sei eine Zufallszahl

Dann lässt sich ein einfacher Vectorgenerator so implementieren

def vgen(vect, rng):
    vect[0] = rng()

    for k in range(1, vect._length):
        vect[k] = vect[k - 1] * 2 + rng()

Zunächst allerdings ein einfacherer Vector, bei dem

b * v = b

gilt.

vect = Vector(8)

current = 1
for pos in range(8):
    vect[pos] = current
    current *= 2

vect
Vector(8, values = [1, 2, 4, 8, 16, 32, 64, 128])

Dann kann das Verschlüsseln ja anfangen...

data = [ v for v in vect.bytes_to_vectors(b"Hallo, Welt!")]
for vector in data:
    print(vector)

encrypted = [vect @ d for d in data]
for enc in encrypted:
    print(enc)
<Vector>([0, 0, 0, 1, 0, 0, 1, 0])
<Vector>([1, 0, 0, 0, 0, 1, 1, 0])
<Vector>([0, 0, 1, 1, 0, 1, 1, 0])
<Vector>([0, 0, 1, 1, 0, 1, 1, 0])
<Vector>([1, 1, 1, 1, 0, 1, 1, 0])
<Vector>([0, 0, 1, 1, 0, 1, 0, 0])
<Vector>([0, 0, 0, 0, 0, 1, 0, 0])
<Vector>([1, 1, 1, 0, 1, 0, 1, 0])
<Vector>([1, 0, 1, 0, 0, 1, 1, 0])
<Vector>([0, 0, 1, 1, 0, 1, 1, 0])
<Vector>([0, 0, 1, 0, 1, 1, 1, 0])
<Vector>([1, 0, 0, 0, 0, 1, 0, 0])
72
97
108
108
111
44
32
87
101
108
116
33
def long_to_bytes(long_, frame_size):
    res = []
    for frame in range(frame_size):
        res.append( (long_ & (0xff << (frame * 8))) >> (frame * 8))
    return  bytes(res)

def bytes_to_long(bytes_):
    res = 0
    for shift, byte in enumerate(bytes_):
          res += byte << (shift * 8)
    return res

def bytes_to_longs(bytes_, frame_size):
    for frame in range(len(bytes_) // frame_size):
        yield bytes_to_long(bytes_[:frame_size])
        bytes_ = bytes_[frame_size:]
def decrypt(int_, vect):
    res = []
    for k in range(len(vect) + 1):
        pos = len(vect) - k
        if(int_ > sum(vect[:pos])):
            res.append(1 << pos)
            int_ -= vect[pos]
    return long_to_bytes(sum(res), vect._length // 8)

decrypted = b"".join([decrypt(enc, vect) for enc in encrypted])
print(decrypted)
b'Hallo, Welt!'

Zusammenschluss

Einen Verschlüsselungsvektor erzeugen und Daten über das Internet verschicken:

import socket, random
# WARNING: DO NOT USE random for real cryptographics!

sender, receiver = socket.socketpair()

vector = Vector(8)


rnd = lambda: random.randint(100, 900)
vgen(vector, rnd)
print(vector)

text = b"Attack in the dawn!"

data = vector.bytes_to_vectors(text)

encrypted = [vector @ d for d in data]

frame_size = max([e.bit_length() for e in encrypted]) // 8 + 1

print(frame_size)


to_send = b"".join([long_to_bytes(enc, frame_size) for enc in encrypted])

print("SENDING", to_send)
l = sender.send(to_send)

received = receiver.recv(l)

received = bytes_to_longs(received, frame_size)


decrypted = b"".join([decrypt(r, vector) for r in received])

print(decrypted)
print(decrypted == text)
<Vector>([539, 1581, 3360, 7182, 14509, 29358, 59169, 119179])
3
SENDING b'<xe9x00x9cx9fx01x9cx9fx01xea[x01x17bx01%~x01xaerx00xf8wx01*x89x01xaerx00x9cx9fx01xddux01nix01xaerx00xeffx01xea[x01xe4xa7x01*x89x01xc9tx00'
b'Attack in the dawn!'
True

Natürlich muss man die frame_size auch mit verschicken!

By The Way

Je größer frame_size und je länger der Verschlüsselungsvector, desto (rechnerisch) sicherer ist die Verschlüsselung.

Wichtig: Der Text muss immer ein Vielfaches von

vector._length // 8

lang sein!

Dazu ein kleines Beispiel:

import socket, random
# WARNING: DO NOT USE random for real cryptographics!

sender, receiver = socket.socketpair()

vector = Vector(64)


rnd = lambda: random.randint(100, 2000)
vgen(vector, rnd)
print(vector)

text = b"Attack in the dawn!\n\nIt is extremely important that no enemies can read this text!\n they could organize a counter strike! padbytes                      "

data = vector.bytes_to_vectors(text)

encrypted = [vector @ d for d in data]

frame_size = max([e.bit_length() for e in encrypted]) // 8 + 1

print(frame_size)


to_send = b"".join([long_to_bytes(enc, frame_size) for enc in encrypted])

print("SENDING", to_send)
l = sender.send(to_send)

received = receiver.recv(l)

received = bytes_to_longs(received, frame_size)


decrypted = b"".join([decrypt(r, vector) for r in received])

print(decrypted)
print(decrypted == text)
<Vector>([128, 882, 2170, 5671, 11444, 23662, 48962, 98372, 197726, 396493, 794771, 1591184, 3184030, 6369705, 12739634, 25480782, 50963541, 101927929, 203856600, 407714803, 815431496, 1630863619, 3261727509, 6523455177, 13046912046, 26093825914, 52187652707, 104375305767, 208750613073, 417501227415, 835002456101, 1670004912562, 3340009825306, 6680019651310, 13360039303451, 26720078608879, 53440157218386, 106880314437538, 213760628876169, 427521257752808, 855042515505866, 1710085031012926, 3420170062027707, 6840340124056388, 13680680248114217, 27361360496229524, 54722720992459275, 109445441984919745, 218890883969840175, 437781767939681524, 875563535879364750, 1751127071758731254, 3502254143517462651, 7004508287034926101, 14009016574069852426, 28018033148139705686, 56036066296279411515, 112072132592558823596, 224144265185117649148, 448288530370235300239, 896577060740470601949, 1793154121480941204010, 3586308242961882409197, 7172616485923764819184])
10
SENDING b"x04xd5xc5xf2xd0xa5mX?x01zxf6xcdxd8<xb3xd9xd8'x01xdcx17xaax85xe47Ax96bx00x16dxbbx97x14xafx00+4x01xf7xd0x1exe1xbbx08xe7x85Ux01Vx1b1x98x975xc2xc2`x01x0b3xafxbdwx87xd913x01x1bW.xb6xcf`x95x1e-x01%x05)x18xbbxb3xf0ebx00xe2xb7x978Txfdxfbxbamx01}x87x1ex85x08xa1x80xc4px01px07jk9x16Ix92Qx01 x93x02:ZYFibx001LMx01Yxbcx0114x01;x96x86Fx1ex9ax9bx154x01xb3{x9f4:xdaxe6xd0ax01]x8exdbxb9xb9xc6x99x96ax00&xbbxdexb8xb9xc6x99x96ax00&xbbxdexb8xb9xc6x99x96ax00"
b'Attack in the dawn!nnIt is extremely important that no enemies can read this text!n they could organize a counter strike! padbytes                      '
True
print(text.decode("UTF-8"))
print("#####################")
print(decrypted.decode("UTF-8"))
Attack in the dawn!

It is extremely important that no enemies can read this text!
 they could organize a counter strike! padbytes
#####################
Attack in the dawn!

It is extremely important that no enemies can read this text!
 they could organize a counter strike! padbytes

Probleme

Das hier ist natürlich kein sicheres Verschlüsselungssystem. Dafür gibt es einige Gründe, nur ein paar davon sind

  • Statistische Angriffe sind sehr leicht.
  • Es is nicht schwer die Frame Size über einen statistischen Angriff heraus zu finden
  • Wenn padbytes nicht zufällig sind(so wie hier) kann man den geheimen Schlüssel leicht herausfinden
  • Es sollten niemals Texte, die größer sind als der geheime Schlüssel verschickt werden, weil der geheime Schlüssel nicht mutiert.
  • Es ist prinzipiell möglich vom verschlüsselten Text auf den geheimen Schlüssel zu schließen.