Python encryption and decryption - python

I trying to use a Python script to decrypt a message. I have the cipher text (noted as FLAG in code) and most of the Python code used for encryption. I need to find the original plaintext message. Below I am trying to build a decode function into my Python code but failing (novice to Python). Can any genius help?
Here's the code so far:
import string
import random
from base64 import b64encode, b64decode
FLAG = '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'
enc_ciphers = ['rot13', 'b64e', 'caesar']
dec_ciphers = ['rot13', 'b64d', 'caesard']
def rot13(s):
_rot13 = string.maketrans(
"zyxwvutsrqponZYXWVUTSRQPONmlkjihgfedcbaMLKJIHGFEDCBA",
"mlkjihgfedcbaMLKJIHGFEDCBAzyxwvutsrqponZYXWVUTSRQPON")
return string.translate(s, _rot13)
def b64e(s):
return b64encode(s)
def b64d(s):
return b64decode(s)
def caesar(plaintext, shift=4):
alphabet = string.ascii_lowercase
shifted_alphabet = alphabet[shift:] + alphabet[:shift]
table = string.maketrans(alphabet, shifted_alphabet)
return plaintext.translate(table)
def caesard(plaintext, shift=-4):
alphabet = string.ascii_lowercase
shifted_alphabet = alphabet[shift:] + alphabet[:shift]
table = string.maketrans(alphabet, shifted_alphabet)
return plaintext.translate(table)
def encode(pt, cnt=50):
tmp = '2{}'.format(b64encode(pt)) #2.format(b64encode(pt))
for cnt in xrange(cnt):
c = random.choice(enc_ciphers) # choose some enc_cipher
i = enc_ciphers.index(c) + 1 # position in the array + 1
_tmp = globals()[c](tmp)
tmp = '{}{}'.format(i, _tmp)
return tmp
def decode(tmp, cnt=50):
for cnt in xrange(cnt):
i = int(tmp[:1])-1
_tmp = tmp[1:]
c = dec_ciphers[i]
tmp = globals()[c](_tmp)
try:
s = b64decode(tmp[1:])
if s.find("flag") != -1:
return s
except:
pass
return b64decode(tmp[1:])
if __name__ == '__main__':
cnt=70
print "Cnt: %d" % cnt
print decode(FLAG, cnt)
Here is the error message:
/usr/bin/python -u "/media/pc/A8560F93560F6204/Python investigation/transfer_csaw2015 fully MODDED2.py"
Cnt: 70
Traceback (most recent call last):
File "/media/pc/A8560F93560F6204/Python investigation/transfer_csaw2015 fully MODDED2.py", line 64, in <module>
print decode(FLAG, cnt)
File "/media/pc/A8560F93560F6204/Python investigation/transfer_csaw2015 fully MODDED2.py", line 47, in decode
i = int(tmp[:1])-1
ValueError: invalid literal for int() with base 10: 'W'

Related

Python - I am getting an error that says 'substring not found'

I am trying to make a transposition cipher encryption function for a class project.
from string import ascii_lowercase
def swap(s: str, index0: int, index1: int):
smaller = index0 if index0 < index1 else index1
bigger = index0 if index0 >= index1 else index1
if bigger >= len(s) or smaller < 0:
return None
ret = s[:smaller] + s[bigger] + s[smaller+1:] # swap first
ret = ret[:bigger] + s[smaller] + s[bigger+1:] # swap second
return ret
def swap_encrypt(s: str, key:str):
ret = s
for key_chr in key:
index = ascii_lowercase.index(key_chr)
swap_this = index % len(ret)
with_this = (swap_this + 1) % len(ret)
ret = swap(ret, swap_this, with_this)
return ret
s = ''
key = ''
def main2():
s = input('Enter your message: ')
s = cleanup(s)
key = input('Enter your keyword: ')
key = cleanup(key)
ret= swap_encrypt((s), (key))
print(cleanup(ret))
main2()
I am getting the error 'substring not found', is there something I am doing wrong?
If my input is =(‘SLOTH POWER’) for s, (‘TOP’) for the key, my output should be: ‘RLOTPOHWES’
Is there also another to limit the functions to ord(), len(), and range()? If so, could I be shown how as well?
error:
Traceback (most recent call last):
File "c:\Users\darks\OneDrive\Documents\7\ciphers.py", line 139, in <module>
main2()
File "c:\Users\darks\OneDrive\Documents\7\ciphers.py", line 136, in main2
ret= swap_encrypt((s), (key))
File "c:\Users\darks\OneDrive\Documents\7\ciphers.py", line 123, in swap_encrypt
index = ascii_lowercase.index(key_chr)
ValueError: substring not found
It can't find the character in the ascii_lowercase, because your input is uppercase. Try "sloth power" instead of "SLOTH POWER", or use s.lower().

Python KeyError(RSA Algorithm)

I am trying to execute this code but I am getting this error:
line 37, in \<module\>
encrypt(encryption_key_pair\[0\],encryption_key_pair\[1\],secret_message
line 22, in encrypt
enc_text = num_trans\[ord_num\]
KeyError: 32
\[Finished in 1.1s\]
Here's the part of the code:
from alphabet import transform, num_trans
from key_generator import generate_keys, encryption_key_pair, decryption_key_pair
#enc_key = [5,14]
#dec_key = [11,14]
secret_message = "abc"
encrypted_message = []
decrypted_message = []
def encrypt(e, modulus, message):
global enc_message
for character in message:
#print(character)
#enc_char = ord(character)
enc_char = transform[f'{character}']
#print(enc_char)
ord_num = (enc_char**e)%modulus
#print(ord_num)
#enc_text = chr(ord_num)
enc_text = num_trans[ord_num]
enc_message = encrypted_message.append(enc_text)
def decrypt(d, modulus, message):
global dec_message
for character in message:
decode_char = transform[f'{character}']
deord_char = (decode_char**d)%modulus
#print(deord_char)
dec_text = num_trans[deord_char]
dec_message = decrypted_message.append(dec_text)
encrypt(encryption_key_pair[0],encryption_key_pair[1],secret_message)
decrypt(decryption_key_pair[0],decryption_key_pair[1],encrypted_message)
print(encrypted_message)
print(decrypted_message)

How to implement HMAC in python without using the hmac library?

I want to implement the hmac algorithm with SHA-1 by the definition from RFC 2104. The code is running but the results aren't the same as the test-vectors from RFC. I'm not sure if I'm loading the values correctly(String to Hex, or String to Bytes?).
As template I've used the pseudo-code from wikipedia
I'm not sure about the terms 'blocksize' and 'output size'. In the code from wikipedia the outputsize is one of the input values but never used.
This is my code so far:
First I'm setting up a hash-function, then I'm converting my input-strings (key and message) into hex values. Next step is to to look if key hast go get hashed or filled with zeros. Next I'm xor-ing the single chars from the key with those values (I don't know where they come from, but they're in every example without any comment). Last but not least I'm combining an inner string(I_key_pad + message) and hash it which results in an outer strings that im combining with the outer pad and hash it again.
import hashlib
from functools import reduce
def hmac(key, message, hashfunc):
hasher = hashlib.sha1
blocksize = 40
message = toHex(message) #is this right?
key = toHex(key)
#alternative: loading values as bytes
#message = bytes(message, 'utf-8')
#key = bytes(key, 'utf-8')
if len(key) > blocksize:
key = hasher(key)
else:
#key = key.ljust(blocksize, '0') #filling from right to left
#key = key.ljust(blocksize, b'\0') #same as above but for bytes
key = pad(key, blocksize) #filling from left to right
val1 = 0x5c
val2 = 0x36
i = 0
o_key_pad = ""
i_key_pad = ""
while i < blocksize:
o_key_pad += str(ord(key[i]) ^ val1)
i_key_pad += str(ord(key[i]) ^ val2)
i += 1
tmp_string = str(i_key_pad) + str(message)
tmp_string = tmp_string.encode()
inner_hash = hasher(tmp_string).hexdigest()
fullstring = str(o_key_pad) + inner_hash
fullstring = fullstring.encode()
fullstring = hasher(fullstring).hexdigest()
print(fullstring)
def pad(key, blocksize):
key = str(key)
while len(key) < blocksize:
key = '0' + key
key = key
return key
def toHex(s):
lst = []
for ch in s:
hv = hex(ord(ch)).replace('0x', '')
if len(hv) == 1:
hv = '0' + hv
lst.append(hv)
return reduce(lambda x, y: x + y, lst)
def main():
while (1):
key = input("key = ")
message = input("message = ")
hash = input("hash (0: SHA-256, 1: SHA-1) = ")
hmac(key, message, hash)
if __name__ == "__main__":
main()
I'm not understanding all the steps in your code, but here's a short example showing HMAC-SHA1 using only hashlib.sha1, with a helper function xor.
import hashlib
def xor(x, y):
return bytes(x[i] ^ y[i] for i in range(min(len(x), len(y))))
def hmac_sha1(key_K, data):
if len(key_K) > 64:
raise ValueError('The key must be <= 64 bytes in length')
padded_K = key_K + b'\x00' * (64 - len(key_K))
ipad = b'\x36' * 64
opad = b'\x5c' * 64
h_inner = hashlib.sha1(xor(padded_K, ipad))
h_inner.update(data)
h_outer = hashlib.sha1(xor(padded_K, opad))
h_outer.update(h_inner.digest())
return h_outer.digest()
def do_tests():
# test 1
k = b'\x0b' * 20
data = b"Hi There"
result = hmac_sha1(k, data)
print(result.hex())
# add tests as desired

SHA256 doesn't yield same result

I'm following on this tutorial and in part 2 (picture below) it shows that the SHA256 yields a result different than what I get when I ran my python code:
the string is: 0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6
While the tutorial SHA256 comes to: 600FFE422B4E00731A59557A5CCA46CC183944191006324A447BDB2D98D4B408
My short python shows:
sha_result = sha256(bitconin_addresss).hexdigest().upper()
print sha_result
32511E82D56DCEA68EB774094E25BAB0F8BDD9BC1ECA1CEEDA38C7A43ACEDDCE
in fact, any online sha256 shows the same python result; so am I missing here something?
You're hashing the string when you're supposed to be hashing the bytes represented by that string.
>>> hashlib.sha256('0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6'.decode('hex')).hexdigest().upper()
'600FFE422B4E00731A59557A5CCA46CC183944191006324A447BDB2D98D4B408'
You could use Gavin's "base58.py", which I believe he no longer shares it on his github page. However you probably could easily google and find different versions of it from github.
Here is one version edited a little by me:
#!/usr/bin/env python
"""encode/decode base58 in the same way that Bitcoin does"""
import math
import sys
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
__b58base = len(__b58chars)
def b58encode(v):
""" encode v, which is a string of bytes, to base58.
"""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += ord(c) << (8*i) # 2x speedup vs. exponentiation
result = ''
while long_value >= __b58base:
div, mod = divmod(long_value, __b58base)
result = __b58chars[mod] + result
long_value = div
result = __b58chars[long_value] + result
# Bitcoin does a little leading-zero-compression:
# leading 0-bytes in the input become leading-1s
nPad = 0
for c in v:
if c == '\0': nPad += 1
else: break
return (__b58chars[0]*nPad) + result
def b58decode(v):
""" decode v into a string of len bytes
"""
long_value = 0L
for (i, c) in enumerate(v[::-1]):
long_value += __b58chars.find(c) * (__b58base**i)
result = ''
while long_value >= 256:
div, mod = divmod(long_value, 256)
result = chr(mod) + result
long_value = div
result = chr(long_value) + result
nPad = 0
for c in v:
if c == __b58chars[0]: nPad += 1
else: break
result = chr(0)*nPad + result
return result
try:
import hashlib
hashlib.new('ripemd160')
have_crypto = True
except ImportError:
have_crypto = False
def hash_160(public_key):
if not have_crypto:
return ''
h1 = hashlib.sha256(public_key).digest()
r160 = hashlib.new('ripemd160')
r160.update(h1)
h2 = r160.digest()
return h2
def hash_160_to_bc_address(h160, version="\x00"):
if not have_crypto:
return ''
vh160 = version+h160
h3=hashlib.sha256(hashlib.sha256(vh160).digest()).digest()
addr=vh160+h3[0:4]
return b58encode(addr)
def public_key_to_bc_address(public_key, version="\x00"):
if not have_crypto or public_key is None:
return ''
h160 = hash_160(public_key)
return hash_160_to_bc_address(h160, version=version)
def sec_to_bc_key(sec, version="\x80"):
if not have_crypto or sec is None:
return ''
vsec = version+sec +"\x01"
hvsec=hashlib.sha256(hashlib.sha256(vsec).digest()).digest()
return b58encode(vsec+hvsec[0:4])
def bc_key_to_sec(prv):
return b58decode(prv)[1:33]
def bc_address_to_hash_160(addr):
bytes = b58decode(addr)
return bytes[1:21]
if __name__ == '__main__':
if len(sys.argv) > 1:
if sys.argv[1] == '-en':
print b58encode(sys.argv[2].decode('hex_codec'))
if sys.argv[1] == '-de':
print b58decode(sys.argv[2]).encode('hex_codec')
if sys.argv[1] == '-pub':
print public_key_to_bc_address(sys.argv[2].decode('hex_codec'))
if sys.argv[1] == '-adr':
print bc_address_to_hash_160(sys.argv[2]).encode('hex_codec')
if sys.argv[1] == '-sec':
print sec_to_bc_key(sys.argv[2].decode('hex_codec'))
if sys.argv[1] == '-prv':
print bc_key_to_sec(sys.argv[2]).encode('hex_codec')
else:
print ''
print 'Usage: ./base58.py [options]'
print ''
print ' -en converts hex to base58'
print ' -de converts base58 to hex'
print
print ' -pub public_key_to_bc_address'
print ' -adr bc_address_to_hash_160'
print
print ' -sec sec_to_bc_key'
print ' -prv bc_key_to_sec'
print
To answer your specific question, based on above code you could use this command:
hashlib.sha256('0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6'.decode('hex_codec')).digest().encode('hex_codec').upper()

Converting .raw file into Hex

I have a .raw image file, and I'd like to use python3 to read all the data from the file and print a hex dump of this image.
If possible, i'd like it to run in the terminal window.
This is the code I have found and adapted so far:
import sys
src = sys.argv[1]
def hexdump( src, length=16, sep='.' ):
result = [];
# Python3 support
try:
xrange(0,1);
except NameError:
xrange = range;
for i in xrange(0, len(src), length):
subSrc = src[i:i+length];
hexa = '';
isMiddle = False;
for h in xrange(0,len(subSrc)):
if h == length/2:
hexa += ' ';
h = subSrc[h];
if not isinstance(h, int):
h = ord(h);
h = hex(h).replace('0x','');
if len(h) == 1:
h = '0'+h;
hexa += h+' ';
hexa = hexa.strip(' ');
text = '';
for c in subSrc:
if not isinstance(c, int):
c = ord(c);
if 0x20 <= c < 0x7F:
text += chr(c);
else:
text += sep;
result.append(('%08X: %-'+str(length*(2+1)+1)+'s |%s|') % (i, hexa, text));
return '\n'.join(result);
if __name__ == "__main__":
print(hexdump(src, length=16, sep='.'))
I've been using the command in the terminal:
python3 nameoffile.py nameofrawfile.raw
and it just gives me the hex values of the name of the raw file. I'd like it to read the raw file then give be all the data from it in hex.
Thanks.
EDIT: I'd like to use python as once the file is represented in hex values, I'd like to do further processing on it using python.
One-liner:
$ python -c \
"import codecs; print(codecs.encode(open('file.raw', 'rb').read(), 'hex').decode())"
The problem is you pass the name of the file to hexdump() which treats it like data. The following corrects that and applies other relatively minor fixes to your code (and seems to work in my limited testing):
try:
xrange
except NameError: # Python3
xrange = range
def hexdump(filename, length=16, sep='.'):
result = []
with open(filename, 'rb') as file:
src = file.read() # Read whole file into memory
for i in xrange(0, len(src), length):
subSrc = src[i:i+length]
hexa = ''
isMiddle = False;
for h in xrange(0,len(subSrc)):
if h == length/2:
hexa += ' '
h = subSrc[h]
if not isinstance(h, int):
h = ord(h)
h = hex(h).replace('0x','')
if len(h) == 1:
h = '0'+h;
hexa += h+' '
hexa = hexa.strip(' ')
text = ''
for c in subSrc:
if not isinstance(c, int):
c = ord(c)
if 0x20 <= c < 0x7F:
text += chr(c)
else:
text += sep;
result.append(('%08X: %-'+str(length*(2+1)+1)+'s |%s|') %
(i, hexa, text))
return '\n'.join(result)
if __name__ == "__main__":
import sys
filename = sys.argv[1]
print(hexdump(filename, length=16, sep='.'))

Categories

Resources