import base64
import re
def encrypt(cleartext, key):
to_return = bytearray(len(cleartext))
for i in xrange(len(cleartext)):
to_return[i] = ord(cleartext[i]) ^ ord(key)
return base64.encodestring(str(to_return))
def decrypt(ciphertxt,key):
x = base64.decodestring(re.escape(ciphertxt))
to_return = bytearray(len(x))
for i in xrange(len(x)):
to_return[i] = ord(x[i]) ^ ord(key)
while to_return[i]>127:
to_return[i]-=127
return to_return
When I encrypt bob then use my decrypt function it returns bob. However for longer things like paragraphs that when encrypted, the cipher text contains \ slashes it does not work. I do not get back ascii characters or base64 characters I get back weird chinese characters or square characters. Please any insight to point me in the right direction will help.
As jasonharper said, you're mangling your Base64 data by calling re.escape on it. Once you get rid of that, your code should be fine. I haven't tested it extensively, but it works correctly for me with multi-line text.
You should also get rid of this from your decrypt function:
while to_return[i]>127:
to_return[i]-=127
It won't do anything if the original cleartext is valid ASCII, but it will mess up the decoding if the cleartext does contain bytes > 127.
However, those functions could be a little more efficient.
FWIW, here's a version that works correctly on both Python 2 and Python 3. This code isn't as efficient as it could be on Python 3, due to the compromises made to deal with the changes in text and bytes handling in Python 3.
import base64
def encrypt(cleartext, key):
buff = bytearray(cleartext.encode())
key = ord(key)
buff = bytearray(c ^ key for c in buff)
return base64.b64encode(bytes(buff))
def decrypt(ciphertext, key):
buff = bytearray(base64.b64decode(ciphertext))
key = ord(key)
buff = bytearray(c ^ key for c in buff)
return buff.decode()
# Test
s = 'This is a test\nof XOR encryption'
key = b'\x53'
coded = encrypt(s, key)
print(coded)
plain = decrypt(coded, key)
print(plain)
Python 3 output
b'Bzs6IHM6IHMycyc2ICdZPDVzCxwBczY9MCEqIyc6PD0='
This is a test
of XOR encryption
Related
I have this code:
from Crypto.Cipher import DES
# Encryption part
key = b'abcdefgh'
def pad(text):
while len(text) % 8 != 0:
text += b' '
return text
des = DES.new(key, DES.MODE_ECB)
text = b'Secret text'
padded_text = pad(text)
encrypted_text = des.encrypt(padded_text)
print(encrypted_text) # FIRST
# Decryption part
that_encrypted_text = input().encode('utf8')
# This print shows the problem---------------
print(that_encrypted_text) # SECOND
# This print shows the problem --------------
data = des.decrypt(that_encrypted_text)
print(data)
From the FIRST print we can see: b'.\x12\x7f\xcf\xad+\xa9\x0c\xc4\xde\x05\x15\xef\x7f\x16\xa0'
Fill in the input(): .\x12\x7f\xcf\xad+\xa9\x0c\xc4\xde\x05\x15\xef\x7f\x16\xa0
From the SECOND print we can see: b'.\\x12\\x7f\\xcf\\xad+\\xa9\\x0c\\xc4\\xde\\x05\\x15\\xef\\x7f\\x16\\xa0'
And after this (because of additional backslashes) an error appears:
ValueError: Data must be aligned to block boundary in ECB mode
Why do additional backslashes appear from encoding and how to get rid of them so that the message was decrypted?
I want both parts of program: encryption and decryption to work separately. That's why there is input() for an encrypted text.
Fill in the input(): .\x12\x7f\xcf\xad+\xa9\x0c\xc4\xde\x05\x15\xef\x7f\x16\xa0
is equivalent to r'.\x12\x7f\xcf\xad+\xa9\x0c\xc4\xde\x05\x15\xef\x7f\x16\xa0' (and it's origin for doubled backslashes in your SECOND print).
Use
that_encrypted_text = (input().encode( 'raw_unicode_escape')
.decode( 'unicode_escape')
.encode( 'latin1'))
See how Python specific text encodings raw_unicode_escape and unicode_escape manipulate with backslashes (and note the role of latin1 encoding there).
I get k_dh from a server as an int:
k_dh = 119503520092559061448841199568006105540928326398312683239977940696158565641455510032815414544631246909440988946150279621651776468095255682411875734678137913094987602893885584001153718721315823055714857464429284631169985212295788520092555311452302786716587927084384268157895132756379511638032100445133977318010
I have to get the last 16 bytes from this and I do this way, converting it in HEX and getting the last 32 HEX chars:
key = str(hex(int(k_dh)))[-32:]
In addition, I receive from the server also the ciphertext:
chipertext = a6e0397f88668030aa861bb09fee236d
I convert it in bytes:
ciphertext = b'\xa6\xe09\x7f\x88f\x800\xaa\x86\x1b\xb0\x9f\xee#m'
using: ciphertext = bytes.fromhex(ciphertext)
And then I try to decrypt without success:
key = unhexlify(key)
IV = Random.new().read(AES.block_size)
decipher = AES.new(key,AES.MODE_CBC,IV)
plaintext = decipher.decrypt(to_decrypt)
print(plaintext)
Which give me b'\x8d]\xd9)I*\x90\xe52\x88\x04\xc7\xcc+8/'.
It should be a readable sentence, something is wrong but I don't know where.
Hope that someone could find my mistake.
Thanks!
I'm trying to create an API with token to communicate between an Raspberry Pi and a Webserver. Right now i'm tring to generate an Token with Python.
from Crypto.Cipher import AES
import base64
import os
import time
import datetime
import requests
BLOCK_SIZE = 32
BLOCK_SZ = 14
#!/usr/bin/python
salt = "123456789123" # Zorg dat de salt altijd even lang is! (12 Chars)
iv = "1234567891234567" # Zorg dat de salt altijd even lang is! (16 Chars)
currentDate = time.strftime("%d%m%Y")
currentTime = time.strftime("%H%M")
PADDING = '{'
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
secret = salt + currentTime
cipher=AES.new(key=secret,mode=AES.MODE_CBC,IV=iv)
encode = currentDate
encoded = EncodeAES(cipher, encode)
print (encoded)
The problem is that the output of the script an exta b' adds to every encoded string.. And on every end a '
C:\Python36-32>python.exe encrypt.py
b'Qge6lbC+SulFgTk/7TZ0TKHUP0SFS8G+nd5un4iv9iI='
C:\Python36-32>python.exe encrypt.py
b'DTcotcaU98QkRxCzRR01hh4yqqyC92u4oAuf0bSrQZQ='
Hopefully someone can explain what went wrong.
FIXED!
I was able to fix it to decode it to utf-8 format.
sendtoken = encoded.decode('utf-8')
You are running Python 3.6, which uses Unicode (UTF-8) for string literals. I expect that the EncodeAES() function returns an ASCII string, which Python is indicating is a bytestring rather than a Unicode string by prepending the b to the string literal it prints.
You could strip the b out of the output post-Python, or you could print(str(encoded)), which should give you the same characters, since ASCII is valid UTF-8.
EDIT:
What you need to do is decode the bytestring into UTF-8, as mentioned in the answer and in a comment above. I was wrong about str() doing the conversion for you, you need to call decode('UTF-8') on the bytestring you wish to print. That converts the string into the internal UTF-8 representation, which then prints correctly.
Here is my case:
# Small hashing script example
import hashlib
import os
def original_pass(Password):
salt = os.urandom(64)
hashed = hashlib.pbkdf2_hmac("sha512", Password.encode(), salt, 300000, dklen = 124)
with open("Hash.txt", "wb") as file:
file.write(salt + b"\n" + hashed)
file.close()
def check_pass(New_Pass):
with open("Hash.txt", "rb") as file:
f = file.readlines()
print (f)
check_hash = hashlib.pbkdf2_hmac("sha512", New_Pass.encode(), f[0].strip(b"\n"), 300000, dklen = 124)
file.close()
if check_hash == f[1]:
return True
else:
return False
original_pass("Password")
print (check_pass("Password"))
My problem is that occasionally the hash will contain characters such as \n. E.G. b"x004\n4\no5". This line gets split into b"x004\n", b"4\no5". This causes errors when I try to read things like the salt, since it may be split up into multiple pieces. Is there any way of avoiding it being read like that, or just stopping it from writing it that way?
To address the duplicate remark
I am dealing specifically with byte strings here and not regular strings. Both are a distinct data type, moreso in python 3 (the version I'm using) as seen here: What is the difference between a string and a byte string?. This distinction means that certain string methods such as .encode() don't work on byte strings. Thus there is a clear difference in the data types I'm dealing with and how they are manipulated, etc...
Based on #Blckknght comment, code using knowledge of fixed length salt:
import hashlib
import os
SALT_LEN = 64
def hash(password,salt):
return hashlib.pbkdf2_hmac('sha512',password.encode(),salt,300000,dklen=124)
def original_pass(password):
salt = os.urandom(SALT_LEN)
hashed = hash(password,salt)
with open('hash.bin','wb') as file:
file.write(salt + hashed)
def check_pass(password):
with open('hash.bin','rb') as file:
data = file.read()
salt,hashed = data[:SALT_LEN],data[SALT_LEN:]
check_hash = hash(password,salt)
return check_hash == hashed
original_pass('Password')
print(check_pass('Password'))
I have tried to build a function that can translate an encrypted string which generated by this function:
def encrypt2(message,key):
return base64.encodestring("".join([chr(ord(message[i]) ^ ord(key[i % len(key)]))
for i in xrange(len(message))]))
So the function take a string and a key which have 4 digits (the key is a string), and encode him using the encodestring function.
The function I build to decode it looks the same but with one difference, the encodestring changes to decodestring. To my opinion it should work, but it prints an error message, "incorrect padding".
What should I change in the decryption function to solve this problem?
def decrypt2(message,key):
return (base64.decodestring("".join([chr(ord(message[i]) ^ ord(key[i % len(key)]))
for i in xrange(len(message))])))
This what I tried to execute:
message = "n"
key = "8080"
encrypt = encrypt2(message,key)
decrypt = decrypt2(encrypt,key)
print "Message: %s \nEncrypt: %s \nDecrypt: %s" %(message,encrypt,decrypt)
and as I said, the line with the decryption returned an "incorrect padding" error.
Your (insecure) "encryption" function returns ordinary base64-encoded text, encoding your ciphertext.
Your decryption function decrypts the input text (which is actually base64), then passes the "decrypted" text to the base64 decoder.
Since the original base64 text is not encrypted, trying to decrypt it results in garbage, which is not valid base64.
To make the suggestions concrete, replace your decoding function like so:
def decrypt2(message,key):
decoded = base64.decodestring(message)
return "".join(chr(ord(decoded[i]) ^ ord(key[i % len(key)]))
for i in xrange(len(decoded)))
There are more efficient ways to do this ;-) For example,
def decrypt2(message, key):
from itertools import cycle
decoded = base64.decodestring(message)
return "".join(chr(a ^ b) for a, b in zip(map(ord, decoded),
cycle(map(ord, key))))