initial commit

This commit is contained in:
2022-10-10 13:00:38 +02:00
commit 18ef4a0515
31 changed files with 2490 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
DES
Plaintext: 02468aceeca86420
Key: 0f1571c947d9e859
Ciphertext: da02ce3a89ecac3b
Change the 4th bit in the plaintext
Plaintext: 12468aceeca86420
Key: 0f1571c947d9e859
Ciphertext: 057cde97d7683f2a => 38e8c912b2bf81ef
Change the 4th bit in the key
Plaintext: 02468aceeca86420
Key: 1f1571c947d9e859
Ciphertext: ee92b50606b62b0b => eae5cedbb5fd55f8
Weak keys
AES
Plaintext: 0123456789abcdeffedcba9876543210
Key: 0f1571c947d9e8590cb7add6af7f6798
Ciphertext:
Change of the 8th bit in the plaintext
Plaintext: 0023456789abcdeffedcba9876543210
Key: 0f1571c947d9e8590cb7add6af7f6798
Ciphertext:
Change of the 8th bit in the key
Plaintext: 0123456789abcdeffedcba9876543210
Key: 0e1571c947d9e8590cb7add6af7f6798
Ciphertext:

47
python/des/README.md Normal file
View File

@@ -0,0 +1,47 @@
pydes
=====
Basic but pure DES implementation in Python
I have written it for fun because nothing else.
How it works ?
--------------
Everything is made within a class called "des". This class can be instanciated once and used to cipher and decipher multiple datas.
It also support padding using the PKCS5 specification. (So the data is padding even if it is multiple of 8 to be sure that the last byte il be padding data).
The generation of all the keys used is made in the method generatekeys and substitute apply the SBOX permutation.
The main method is run which is called by both encrypt and decrypt but in a different mode. This method do basically all the stuff, it loop
throught all the blocks and for each do the 16th rounds.
Be careful: This module implement DES in ECB mode, so you can't make it weaker. I didn't made it to be strong but for fun.
How to use it ?
---------------
I have not done any interface to take argument in command line so this module can't be used as a script. (feel free to modify it).
To use it from python shell or in another module do:
from pydes import des
key = "secret_k"
text= "Hello wo"
d = des()
ciphered = d.encrypt(key,text)
plain = d.decrypt(key,ciphered)
print "Ciphered: %r" % ciphered
print "Deciphered: ", plain
Note: In this exemple no padding is specified so you have to provide a text which is multiple of 8 bytes. The key is cut to 8 bytes if longer.
To use padding:
from pydes import des
key = "secret_k"
text= "Hello world !"
d = des()
ciphered = d.encrypt(key,text,padding=True) #Or just True in third arg
plain = d.decrypt(key,ciphered,padding=True)
print "Ciphered: %r" % ciphered
print "Deciphered: ", plain

270
python/des/pydes.py Normal file
View File

@@ -0,0 +1,270 @@
# -*- coding: utf8 -*-
import binascii
# Initial permut matrix for the datas
PI = [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]
# Initial permut made on the key
CP_1 = [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]
# Permut applied on shifted key to get Ki+1
CP_2 = [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]
# Expand matrix to get a 48bits matrix of datas to apply the xor with Ki
E = [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]
# SBOX
S_BOX = [
[[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],
],
[[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],
],
[[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],
],
[[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],
],
[[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],
],
[[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],
],
[[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],
],
[[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],
]
]
# Permut made after each SBox substitution for each round
P = [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]
# Final permut for datas after the 16 rounds
PI_1 = [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]
# Matrix that determine the shift for each round of keys
SHIFT = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
def string_to_bit_array(text): # Convert a string into a list of bits
array = list()
for char in text:
binval = binvalue(char, 8) # Get the char value on one byte
array.extend([int(x) for x in list(binval)]) # Add the bits to the final list
return array
def bit_array_to_string(array): # Recreate the string from the bit array
res = ''.join([chr(int(y, 2)) for y in [''.join([str(x) for x in bytes]) for bytes in nsplit(array, 8)]])
return res
def binvalue(val, bitsize): # Return the binary value as a string of the given size
binval = bin(val)[2:] if isinstance(val, int) else bin(ord(val))[2:]
if len(binval) > bitsize:
raise "binary value larger than the expected size"
while len(binval) < bitsize:
binval = "0" + binval # Add as many 0 as needed to get the wanted size
return binval
def nsplit(s, n): # Split a list into sublists of size "n"
return [s[k:k + n] for k in range(0, len(s), n)]
ENCRYPT = 1
DECRYPT = 0
class des():
def __init__(self):
self.password = None
self.text = None
self.keys = list()
def run(self, key, text, action=ENCRYPT, padding=False):
if len(key) < 8:
raise "Key Should be 8 bytes long"
elif len(key) > 8:
key = key[:8] # If key size is above 8bytes, cut to be 8bytes long
self.password = key
self.text = text
if padding and action == ENCRYPT:
self.addPadding()
elif len(self.text) % 8 != 0: # If not padding specified data size must be multiple of 8 bytes
raise "Data size should be multiple of 8"
self.generatekeys() # Generate all the keys
text_blocks = nsplit(self.text, 8) # Split the text in blocks of 8 bytes so 64 bits
result = list()
for block in text_blocks: # Loop over all the blocks of data
block = string_to_bit_array(block) # Convert the block in bit array
block = self.permut(block, PI) # Apply the initial permutation
g, d = nsplit(block, 32) # g(LEFT), d(RIGHT)
tmp = None
for i in range(16): # Do the 16 rounds
d_e = self.expand(d, E) # Expand d to match Ki size (48bits)
if action == ENCRYPT:
tmp = self.xor(self.keys[i], d_e) # If encrypt use Ki
else:
tmp = self.xor(self.keys[15 - i], d_e) # If decrypt start by the last key
tmp = self.substitute(tmp) # Method that will apply the SBOXes
tmp = self.permut(tmp, P)
tmp = self.xor(g, tmp)
g = d
d = tmp
print(g, end="")
print(d)
print(hex(int("".join(str(x) for x in g+d), 2)))
result += self.permut(d + g, PI_1) # Do the last permut and append the result to result
print(" -------- ")
print("Result : ",result)
print(hex(int("".join(str(x) for x in result), 2)))
print()
final_res = bit_array_to_string(result)
if padding and action == DECRYPT:
return self.removePadding(final_res) # Remove the padding if decrypt and padding is true
else:
return final_res # Return the final string of data ciphered/deciphered
def substitute(self, d_e): # Substitute bytes using SBOX
subblocks = nsplit(d_e, 6) # Split bit array into sublist of 6 bits
result = list()
for i in range(len(subblocks)): # For all the sublists
block = subblocks[i]
row = int(str(block[0]) + str(block[5]), 2) # Get the row with the first and last bit
column = int(''.join([str(x) for x in block[1:][:-1]]), 2) # Column is the 2,3,4,5th bits
val = S_BOX[i][row][column] # Take the value in the SBOX appropriated for the round (i)
bin = binvalue(val, 4) # Convert the value to binary
result += [int(x) for x in bin] # And append it to the resulting list
return result
def permut(self, block, table): # Permut the given block using the given table (so generic method)
return [block[x - 1] for x in table]
def expand(self, block, table): # Do the exact same thing than permut but for more clarity has been renamed
return [block[x - 1] for x in table]
def xor(self, t1, t2): # Apply a xor and return the resulting list
return [x ^ y for x, y in zip(t1, t2)]
def generatekeys(self): # Algorithm that generates all the keys
self.keys = []
key = string_to_bit_array(self.password)
key = self.permut(key, CP_1) # Apply the initial permut on the key
g, d = nsplit(key, 28) # Split it in to (g->LEFT),(d->RIGHT)
for i in range(16): # Apply the 16 rounds
g, d = self.shift(g, d, SHIFT[i]) # Apply the shift associated with the round (not always 1)
tmp = g + d # Merge them
self.keys.append(self.permut(tmp, CP_2)) # Apply the permut to get the Ki
def shift(self, g, d, n): # Shift a list of the given value
return g[n:] + g[:n], d[n:] + d[:n]
def addPadding(self): # Add padding to the datas using PKCS5 spec.
pad_len = 8 - (len(self.text) % 8)
self.text += pad_len * chr(pad_len)
def removePadding(self, data): # Remove the padding of the plain text (it assume there is padding)
pad_len = ord(data[-1])
return data[:-pad_len]
def encrypt(self, key, text, padding=False):
return self.run(key, text, ENCRYPT, padding)
def decrypt(self, key, text, padding=False):
return self.run(key, text, DECRYPT, padding)
def flip(txt, pos):
if len(text) > pos:
if txt[pos] == 1:
txt[pos] = 0
else:
txt[pos] = 1
if __name__ == '__main__':
key_hex = b'02468aceeca86420'
key = binascii.unhexlify(key_hex)
text_hex = b'0f1571c947d9e859'
text = binascii.unhexlify(text_hex)
print(text)
d = des()
r = d.encrypt(key, text)
r2 = d.decrypt(key, r)
print("Ciphered: %r" % r)
print("Ciphered: %r" % binascii.hexlify(r.encode('latin1')))
print("Deciphered: %r" % r2)
print("Deciphered: %r" % binascii.hexlify(r2.encode('latin1')))

View File

@@ -0,0 +1,268 @@
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 3 15:30:59 2019
This module converts string to hex, hex to string, ...
@author: Patrice MEGRET
"""
import binascii
def hex_to_string(h, show='y', coding='Latin-1'):
"""Conversion from hex to string.
Args:
h: hexa string
show: print conversion (default 'y')
coding: string coding (default 'Latin-1')
Returns:
h_s: string coded with coding
Internal:
h_by: h in byte
"""
h_by = binascii.unhexlify(h)
h_s = h_by.decode(coding)
if show == "y":
print("Hex = ", h, "Len = ", len(h))
print("Bytes = ", h_by, "Len = ", len(h_by))
print('{0} = {1}, Len = {2!r}'.format(coding, h_s, len(h_s)))
print('ASCII = {0!a}, Len = {1}'.format(h_s, len(h_s)))
print("\n")
return h_s
def hex_to_byte(h, show='y', coding='Latin-1'):
"""Conversion from hex to byte.
Args:
h: hexa string
show: print conversion (default 'y')
coding: string coding (default 'Latin-1')
Returns:
h_by: h in byte
"""
h_by = binascii.unhexlify(h)
if show == "y":
print("Hex = ", h, "Len = ", len(h))
print("Bytes = ", h_by, "Len = ", len(h_by))
print("\n")
return h_by
def string_to_hex(s, show="y", coding="Latin-1"):
"""Conversion from string to hex.
Args:
s: string
show: print conversion (default 'y')
coding: string coding (default 'Latin-1')
Returns:
s_h: string in hexa
Internal:
s_by: s in byte with coding
"""
s_by = s.encode(coding)
s_h = binascii.hexlify(s_by)
if show == "y":
print('ASCII = {0!a}, Len = {1}'.format(s, len(s)))
print('{0} = {1}, Len = {2!r}'.format(coding, s, len(s)))
print("Bytes = ", s_by, "Len = ", len(s_by))
print("Hex = ", s_h, "Len = ", len(s_h))
print("\n")
return s_h
def byte_to_hex(b, show="y", coding="Latin-1"):
"""Conversion from byte to hex.
Args:
b: bytes
show: print conversion (default 'y')
coding: string coding (default 'Latin-1')
Returns:
b_h: string in hexa
"""
b_h = binascii.hexlify(b)
if show == "y":
print("Bytes = ", b, "Len = ", len(b))
print("Hex = ", b_h, "Len = ", len(b_h))
print("\n")
return b_h
def hex_to_bin(h, show="y"):
"""Conversion from hex to bin.
Args:
h: hexa string
show: print conversion (default 'y')
Returns:
b: binary equivalent of h
"""
b = bin(int(h, 16)) # b is a string beginning with 0b
if show == "y":
print("Bin = ", b, "Len = ", len(b) - 2)
print('\n')
return b
def hex_to_bin_des(h, show="y"):
"""Conversion from hex to bin and display 64 bits.
Args:
h: hexa string
show: print conversion (default 'y')
Returns:
b: binary equivalent of h
"""
b = bin(int(h, 16)) # b is a string beginning with 0b
if show == "y":
print('Bin = {0:064b}'.format(int(h, 16)))
print('\n')
return b
def bin_to_hex(b, show="y"):
"""Conversion bin to hex.
Args:
b: binary string
show: print conversion (default 'y')
Returns:
h: hexa equivalent of h
"""
h = hex(int(b, 2)) # h is a string beginning with 0x
if show == "y":
print("Hex = ", h, "Len = ", len(h) - 2)
print('\n')
return h
def bin_to_hex_des(b, show="y"):
"""Conversion bin to hex and display 16 hexa.
Args:
b: binary string
show: print conversion (default 'y')
Returns:
h: hexa equivalent of h
"""
h = hex(int(b, 2)) # h is a string beginning with 0x
if show == "y":
print('Hex = {:016x}'.format(int(b, 2)))
print('\n')
return h
def xor_hex(h1_str, h2_str):
"""Xor between two hexa strings.
Args:
h1_str: hexa string 1
h2_str: hexa string 2
Returns:
print xor between the two hexa strings
"""
i1 = int(h1_str, 16)
i2 = int(h2_str, 16)
x = i1 ^ i2
xb_str = bin(x)
n1 = xb_str.count('1')
print(xb_str, n1)
print('\n')
def binvalue(val, bitsize):
"""Return the binary value as a string of a given size.
Args:
val: integer or one character
bitsize: number of bits for the conversion
Returns:
binval: string of bitsize-length
"""
# bin returns a string beginning with 0b ==> extract [2:] to cut these two characters
binval = bin(val)[2:] if isinstance(val, int) else bin(ord(val))[2:]
if len(binval) > bitsize:
raise "binary value larger than the expected size"
while len(binval) < bitsize:
binval = "0" + binval # Add as many 0 as needed to get the wanted size
return binval
def hexvalue(val, hexsize):
"""Return the hex value as a string of the given size.
Args:
val: integer or one character
hexsize: number of hex for the conversion
Returns:
hexval: string of hexsize-length
"""
# hex returns a string beginning with 0x ==> extract [2:] to cut these two characters
hexval = hex(val)[2:] if isinstance(val, int) else hex(ord(val))[2:]
if len(hexval) > hexsize:
raise "hex value larger than the expected size"
while len(hexval) < hexsize:
hexval = "0" + hexval # Add as many 0 as needed to get the wanted size
return hexval
def string_to_hex_array(text):
"""Convert a string into a list of hex.
Args:
text: string
Returns:
array: array of hexvalues
"""
array = list()
for char in text:
hexval = hexvalue(char, 2) # Get the char value on two hex
array.extend([x for x in list(hexval)]) # Add the hex to the final list
return array
def hex_array_to_string(array):
"""Recreate the string from the hex array.
Args:
array: array of hex
Returns:
res: string
"""
res = ''.join([chr(int(y, 16)) for y in [''.join([str(x) for x in hexa]) for hexa in nsplit(array, 2)]])
return res
def bit_array_to_hex(array, bitgroup, hexsize):
"""Return the hex value from an array of bits.
Args:
array: array of bits
bitgroup: number of bits to be grpoupo for the conversion
hexsize: number of hex for the conversion of bitgroup bits
Returns:
res: string of hex
"""
res = ''.join(
[hexvalue(int(y, 2), hexsize) for y in [''.join([str(x) for x in hexa]) for hexa in nsplit(array, bitgroup)]])
return res
def nsplit(s, n): # Split a list into sublists of size "n"
return [s[k:k + n] for k in range(0, len(s), n)]
if __name__ == '__main__':
hs = b'370FFF'
hex_to_string(hs)
ss = 'test é'
string_to_hex(ss)
hex_to_bin('FF')
bin_to_hex('1111')
xor_hex('FF', '11')