Deo Valiandro. M

Data Encryption Standard (DES)

Friends don’t spy; true friendship is about privacy, too.

– Stephen King

Algoritma DES dikembangkan di IBM dibawah kepemimpinan W.L. Tuchman pada tahun 1972. Algoritma ini didasarkan pada algoritma Lucifer yang dibuat oleh Horst Feistel.

DES termasuk ke dalam sistem kriptografi simetri dan tergolong jenis cipher blok.

DES beroperasi pada ukuran blok 64 bit. DES mengenkripsikan 64 bit plainteks menjadi 64 bit cipherteks dengan menggunakan 56 bit kunci internal (internal key) atau upa-kunci (subkey). Kunci internal dibangkitkan dari kunci eksternal (external key) yang panjangnya 64 bit.

Implementasi dengan menggunakan Python:

ip = [58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
      62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
      57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
      61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7]

ip_inv = [40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
          38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
          36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
          34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25]

expansion = [32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
             8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
             16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
             24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1]

permutation_box = [16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
                   2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25]


def d(lis):
    return "".join(str(x) for x in lis)


def rotate_left(data, n):
    return data[n:] + data[:n]


def str2bin(msg):
    dummy = []
    for i in range(len(msg)):
        bits = bin(ord(msg[i]))[2:]
        bits = '00000000'[len(bits):] + bits
        dummy.extend([int(b) for b in bits])
    return dummy


def key_builder(ext_key):
    pc1 = [57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
           10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
           63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
           14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4]

    pc2 = [14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
           23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
           41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
           44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32]

    key_round = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

    raw_result = []
    final_key = []

    for i in range(len(pc1)):
        raw_result.append(ext_key[pc1[i] - 1])

    left = raw_result[:28]
    right = raw_result[28:]

    for i in range(len(key_round)):
        left = rotate_left(left, key_round[i])
        right = rotate_left(right, key_round[i])
        ki = left + right
        aur = []
        for j in range(len(pc2)):
            aur.append(ki[pc2[j] - 1])
        final_key.append(aur)

    return final_key


def split_message(msg):
    msg_split = []

    j = 0
    for i in range(0, len(msg), 64):
        msg_split.append(msg[i:i + 64])

        if len(msg_split[j]) < 64:
            miss = 64 - len(msg_split[j])
            padding = "".join(str(int(x * 0)) for x in range(miss))
            msg_split[j].extend([int(b) for b in padding])
        j += 1

    return msg_split


def permutation_function(msg, table):
    dummy = []
    for i in range(len(table)):
        dummy.append(msg[table[i] - 1])

    return dummy


def xor_with_key(msg, key_f):
    dummy = []
    for i in range(len(msg)):
        dummy.append(msg[i] ^ key_f[i])

    return dummy


def s_box(msg):
    s1 = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, ],
          [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, ],
          [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, ],
          [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, ], ]

    s2 = [[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, ],
          [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, ],
          [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, ],
          [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, ], ]

    s3 = [[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, ],
          [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, ],
          [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, ],
          [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, ], ]

    s4 = [[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, ],
          [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, ],
          [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, ],
          [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, ], ]

    s5 = [[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, ],
          [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, ],
          [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, ],
          [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, ], ]

    s6 = [[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, ],
          [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, ],
          [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, ],
          [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, ], ]

    s7 = [[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, ],
          [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, ],
          [1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, ],
          [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, ], ]

    s8 = [[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, ],
          [1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, ],
          [7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, ],
          [2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11, ], ]

    s = [s1, s2, s3, s4, s5, s6, s7, s8]

    b = []
    index = 0
    for k in range(8):
        ar = msg[index:index + 6]
        index += 6
        row = int(str(ar[0]) + str(ar[5]), 2)
        column = int(''.join([str(x) for x in ar[1:5]]), 2)
        value = bin(s[k][row][column])[2:]
        value = '0000'[len(value):] + value
        b.extend([int(x) for x in value])

    return b


def encrypt(messages, internal_key):
    messages = split_message(messages)
    cipher = ""

    for msg in messages:
        permutation = permutation_function(msg, ip)
        left, right = permutation[:32], permutation[32:]

        for i in range(16):
            expand = permutation_function(right, expansion)
            vector_a = xor_with_key(expand, internal_key[i])
            vector_b = s_box(vector_a)
            pb = permutation_function(vector_b, permutation_box)
            temp = right
            right = []
            for k in range(len(pb)):
                right.append(pb[k] ^ left[k])
            left = temp

        raw = right + left
        final = permutation_function(raw, ip_inv)
        cipher += "".join(str(x) for x in final)

    return cipher


def decrypt(messages, internal_key):
    messages = split_message(messages)
    plaintext = ""

    for msg in messages:
        permutation = permutation_function(msg, ip)
        left, right = permutation[:32], permutation[32:]

        for i in range(15, -1, -1):
            expand = permutation_function(right, expansion)
            vector_a = xor_with_key(expand, internal_key[i])
            vector_b = s_box(vector_a)
            pb = permutation_function(vector_b, permutation_box)
            temp = right
            right = []
            for k in range(len(pb)):
                right.append(pb[k] ^ left[k])
            left = temp

        raw = right + left
        final = permutation_function(raw, ip_inv)
        plaintext += "".join(str(x) for x in final)

    return plaintext


# open key
externalKey = open('pass.txt', 'r').read()
key_in_binary = str2bin(externalKey)
key = key_builder(key_in_binary)

# message 8-byte (text)
# message = open('message.txt', 'r').read()
# message = str2bin(message)

# message in json (more than 8-byte)
message = open('example.json', 'r').read()
message = str2bin(message)

# encrypt message
ciphertext = encrypt(message, key)
print("Ciphertext =", ciphertext)

aa = []
aa.extend([int(x) for x in ciphertext])

# decrypt message
print("Plaintext =", d(message))
print("Plaintext =", decrypt(aa, key))