Issues when decrypting data received from GET python - python

I am developing a new payment_acquirer module for Odoo, and since last week, I am always getting an error when I try to decrypt data that I received through the server.
When I copy the data in an another python file to test, it seems to be working perfectly with the same data, but when I do it in my controller, it returns an error.
This is the code inside my controller :
#http.route('/payment/ariarynet/result', type='http', auth="none", methods=['POST', 'GET'], csrf=False)
def ariarynet_result(self, **post):
""" Handle Ariary.net response and redirect to form_validate"""
_logger.info('Beginning Ariary.net form_feedback with post data %s', pprint.pformat(post)) # debug
key = bytes("477c3551da64136491eff1cb6ab27be35093b2512eb78f2c8d"[:24])
params = dict(post)
raw = b"%s"%post.get('idpanier')
decode = raw.encode('utf8')
idpanier = main.Utils().decrypt(key,decode) #it return an error
When executed, I have the following error:
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n.")
ValueError: Invalid data length, data must be a multiple of 8 bytes
I am using pyDes module to crypt and decrypt data.
This is the test that is working :
def test_bytes(self):
key = bytes("477c3551da64136491eff1cb6ab27be35093b2512eb78f2c8d"[:24])
expect = "12177"
raw = "%8E%16%B8n%A6%1F%2Fj" #this is the data that I copied from the url
text = urllib.unquote(raw)
byteArray = bytes(text)
print Utils().decrypt(key, text)
self.assertEqual(expect,Utils().decrypt(key, text), "%s est diférent de %s" % (expect, Utils().decrypt(key, text)) )
I really need your help to figure out what am I doing wrong.
Update:
I think that the probleme have to do with the character encoding, because when I am trying to compare the data I get with the excpected one, I don't get the same thing:
param = post.get('idpanier')
text = (param.encode('utf8'))
print "utf8 encode %s, hex encoded text %s" % (text, text.encode('hex'))
print "utf8 encode %s, hex encoded text %s" % ("b4227475d651420b".decode('hex'), "b4227475d651420b") #excpected behavior
Here is the output:
utf8 encode �"tu�QB
, hex encoded text efbfbd227475efbfbd51420b
utf8 encode �"tu�QB
, hex encoded text b4227475d651420b

The solution I found : instead of retriving parameters with post.get(), I have manage to get the real parameters data through the incoming url directly, where parameters encoding is not changed yet.
query = parse_qs("http://url?%s"%request.httprequest.query_string) #append the query string to a dummy url to get a well formed url
param = query.get('idpanier')
After that, everything worked fine.

Related

Get output from tn.write() during telnet using telnetlib

tl/dr: Is there a simple way to get a command's output during a telnet session with Python?
I am writing a Python script (using 3.4) to automate actions during a telnet session. I want to be able to telnet in, write to the command line to perform an action, and then return the output from that command. I have a method, but it seems like it could be improved upon, and it is not very dynamic.
My current method:
def telnet_in(ip):
"""Telnets into the device"""
tn = telnetlib.Telnet(ip)
tn.read_until(b"login: ")
tn.write(TEL_PASS)
tn.read_until(PROMPT) # Clear buffer of output
return tn
This will telnet into my device just fine for my setup.
The next part I try to cat some information from the device:
def get_model(ip):
"""Returns the device's model"""
session = telnet_in(ip)
session.write(b"cat " + MODEL_DIR + b"model\r\n")
time.sleep(1) # Give it time to enter buffer
model = session.read_very_eager()
model = model[26:-4] # Clean up output to only return model
model = decode_byte_str(model) # Decode to str
telnet_exit(session)
return model
A few things I have noticed/tried:
I have to use the byte str 'b' for when I use tn.write()
I have to use \r as well.
Without those, I do not get a return or I get an error.
Additionally:
The output I get from model = session.read_very_eager() will return the string that I used for my command as well as the prompt after the command's returned output. I have to trim the string down to size to just get the model str.
Given that I have to use 'b' for my strings, the string returned is also a byte string and needs to be decoded. I handle that with my decode_byte_str() just fine:
def decode_byte_str(byte_str):
"""Decodes a byte string using utf-8"""
return byte_str.decode("utf-8")
I am able to get the string in the end that I am looking for, but it seems to be such a convoluted way to just get a returned string. Also, this method is not dynamic, and I have to write individual functions for each info that I want to obtain, given that I have to trim the strings to a certain size. Certainly, I could just "pass" the size that needs to be trimmed, but that is additional work that really shouldn't be needed. Further, if I want to write a function that takes a variable that the user inputs, then I wouldn't know the exact amount to trim before the output. I suppose I could get the length of the str, and then pass that length in, but again that further complicates what should be a simple task.
So, my question is: Is there a simple way to get the command's output during a telnet session with Python? Also, I am not married to using telnetlib. If there is a better lib or method then I am open to those as well.
Thanks in advance!
EDIT:
Here is my updated version, if anyone wants to use it until we can find an easier/better way:
def telnet_in(ip):
"""Telnets into a device"""
tn = telnetlib.Telnet(ip)
tn.read_until(b"login: ")
tn.write(TEL_PASS)
tn.read_until(PROMPT) # Clear buffer of output
return tn
def telnet_exit(session):
"""Exits a telnet session"""
session.write(b"exit\r\n")
def _encode_str(in_str):
"""Encodes a string to a byte string"""
return bytes(in_str, encoding="utf-8")
def _decode_byte_str(byte_str):
"""Decodes a byte string using utf-8"""
return byte_str.decode("utf-8")
def _get_cmd_output(session, cmd_str):
"""Returns output from a command"""
cmd_str_len = len(cmd_str)
bcmd_str = _encode_str(cmd_str) # Encode str to byte str
session.write(bcmd_str)
time.sleep(0.1) # Give it time to enter buffer
cmd_out = session.read_very_eager()
cmd_out = cmd_out[cmd_str_len:PROMPT_LEN] # Trim output to only return command's returned output
cmd_out = _decode_byte_str(cmd_out) # Decode to a str
return cmd_out
def get_model(ip):
"""Returns the device's model"""
session = telnet_in(ip)
cat_model = "cat " + INFO_DIR + "model\r\n"
model = _get_cmd_output(session, cat_model)
telnet_exit(session)
return model
def get_device_id(ip):
"""Returns the device id"""
session = telnet_in(ip)
cat_device_id = "cat " + INFO_DIR + "device_id\r\n"
device_id = _get_cmd_output(session, cat_device_id)
telnet_exit(session)
return device_id
Works for my purposes. I still wonder if there is already some built-in lib that can already handle this stuff.

Itarate password combinations to find key for string

I´m having problems to brute force the key for a string encrypted with RC4/ARC4.
This is the encrypted string:
E7Ev08_MEojYBixHRKTKQnRSC4hkriZ7XPsy3p4xAHUPj41Dlzu9
And the string is also hashed with base64, so complete encoded string is:
RTdFdjA4X01Fb2pZQml4SFJLVEtRblJTQzRoa3JpWjdYUHN5M3A0eEFIVVBqNDFEbHp1OQ==
#-*- coding: utf-8 -*-
import threading
import sys
import time
import re
import itertools
from itertools import product
from Crypto.Cipher import ARC4
import base64
def special_match(strg):
try:
strg.decode('utf-8')
except UnicodeDecodeError:
pass
else:
print('\nkey found at %s, key: %s' % (time.ctime(), rc4_key))
try:
f=open('key.txt','ab')
f.write('Key (%s): %s\n' % (time.ctime(), rc4_key))
f.write('Decrypted string: ' + strg + '\n')
f.close()
except Exception as e:
print('ERROR WRITING KEY TO FILE: ' + str(e))
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
end_chars = chars[::-1][0:7]
encoded_string = 'RTdFdjA4X01Fb2pZQml4SFJLVEtRblJTQzRoa3JpWjdYUHN5M3A0eEFIVVBqNDFEbHp1OQ=='
spinner = itertools.cycle(['-', '/', '|', '\\'])
while 1:
try:
# Iteration processess of possibel keys
for length in range(7,8): # only do length of 7
for attempt in itertools.permutations(chars, length):
rc4_key = ''.join(attempt) # This key is unknown, we are looking for it..
Ckey = ARC4.new(rc4_key)
decoded = Ckey.decrypt(encoded_string.decode('base64'))
special_match(decoded)
sys.stdout.write(spinner.next()) # write the next character
sys.stdout.flush() # flush stdout buffer (actual character display)
sys.stdout.write('\b') # erase the last written char
# Exit the script when we have done all password-combination-iterations
if (rc4_key == end_chars):
print('iteration of combinations done! No key found.. :(\n' + time.ctime())
exit()
except KeyboardInterrupt:
print('\nKeybord interrupt, exiting gracefully anyway on %s at %s' % (rc4_key, time.ctime()))
sys.exit()
I´m using http://crypo.bz.ms/secure-rc4-online to encrypt the string and https://www.base64encode.org to encode it with UTF-8.
Question
Why doesn't my script work to find the key?
(Im not receiving any error message, it is more of a general question if I have missed something in my code, or approach of the problem.)
plaintext: This is something that I have encrypted, key: ABCFMSG
Alright, it seems that crypo.bz uses a realy weird system. Basically they have a really weird encoding which causes discrepancies if you simply use their characters.
For example encoding 'a' with key 'A' should produce a character with value 163.
In hex A3. In crypo.bz we get 'oc' instead.
So you have two possibilities. Either do some ciphertext analysis or use another site. I recommend this one as they tell you in what they encode the result:
http://www.fyneworks.com/encryption/RC4-Encryption/index.asp
Take the hex and convert it to string, the you should be able to decipher it
Your code seems to be working by the way ;)
Tell me if you have additional questions
EDIT: did some additional analysis, and it is really, really weird.
in crypo.bz IF the algorithm is correct 163 is oc
160 is nc
but 161 is mc ??
If anyone figures this out please tell me!
EDITEDIT:
here is the encrypted, but not encoded string '#ÔèïH§¢6pbpÊ]õªœIôŒ>Yœ5îfäGuæxÖa…ë6°'
Your program takes like half a second to find the key ;)

Invalid continuation byte saving cipher

I have the following function to create cipher text and then save it:
def create_credential(self):
des = DES.new(CIPHER_N, DES.MODE_ECB)
text = str(uuid.uuid4()).replace('-','')[:16]
cipher_text = des.encrypt(text)
return cipher_text
def decrypt_credential(self, text):
des = DES.new(CIPHER_N, DES.MODE_ECB)
return des.decrypt(text)
def update_access_credentials(self):
self.access_key = self.create_credential()
print repr(self.access_key) # "\xf9\xad\xfbO\xc1lJ'\xb3\xda\x7f\x84\x10\xbbv&"
self.access_password = self.create_credential()
self.save()
And I will call:
>>> from main.models import *
>>> u=User.objects.all()[0]
>>> u.update_access_credentials()
And this is the stacktrace I get:
UnicodeDecodeError: 'utf8' codec can't decode byte 0xf5 in position 738: invalid start byte
Why is this occurring and how would I get around it?
You are storing a bytestring into a Unicode database field, so it'll try and decode to Unicode.
Either use a database field that can store opaque binary data, decode explicitly to Unicode (latin-1 maps bytes one-on-one to Unicode codepoints) or wrap your data into a representation that can be stored as text.
For Django 1.6 and up, use a BinaryField, for example. For earlier versions, using a binary-to-text conversion (such as Base64) would be preferable over decoding to Latin-1; the result of the latter would not give you meaningful textual data but Django may try to display it as such (in the admin interface for example).
It's occurring because you're attempting to save non-text data in a text field. Either use a non-text field instead, or encode the data as text via e.g. Base-64 encoding.
Using base64 encoding and decoding here fixed this:
import base64
def create_credential(self):
des = DES.new(CIPHER_N, DES.MODE_ECB)
text = str(uuid.uuid4()).replace('-','')[:16]
cipher_text = des.encrypt(text)
base64_encrypted_message = base64.b64encode(cipher_text)
return base64_encrypted_message
def decrypt_credential(self, text):
text = base64.b64decode(text)
des = DES.new(CIPHER_N, DES.MODE_ECB)
message = des.decrypt(text)
return message

Python Urllib Urlopen won't return after new line?

I'm trying to get authenticated by an API I'm attempting to access. I'm using urllib.parse.urlencode to encode the parameters which go in my URL. I'm using urllib.request.urlopen to fetch the content.
This should return 3 values from the server, such as:
SID=AAAAAAAAAAA
LSID=BBBBBBBBBBB
AUTH=CCCCCCCCCCC
The problem is it only returns the first value, and the trailing new line character.
import urllib.request
import urllib.parse
Emailparamx = 'Email'
Emailparam = Emailparamx.encode('utf-8')
email = 'myemail#stackoverflow.com'
email = email.encode('utf-8')
Passwdparam = 'Passwd'
Passwdparam = Passwdparam.encode('utf-8')
password = 'hidden'
password = password.encode('utf-8')
Accounttypeparam = 'accountType'
Accounttypeparam = Accounttypeparam.encode('utf-8')
accounttype = 'GOOGLE'
accounttype = accounttype.encode('utf-8')
Serviceparam = 'service'
Serviceparam = Serviceparam.encode('utf-8')
service = 'adwords'
service = service.encode('utf-8')
url = 'https://accounts.google.com/ClientLogin?'
urlen = url.encode('utf-8')
data = [(Emailparamx, email), (Passwdparam, password),
(Accounttypeparam, accounttype), (Serviceparam, service)]
auth = ''
dataurl = urllib.parse.urlencode(data)
accessurl = (url + "%s" % dataurl)
fh = urllib.request.urlopen(accessurl)
equals = '='
eqenc = equals.encode('utf-8')
try:
msg = fh.readline().split(eqenc)
print (msg)
And then msg prints
[b'SID', b'AAAAAAAAAAAAAAAAA\n']
I know that's some seriously ugly code, I'm about a week old in Python. Any help would be greatly appreciated.
The problem is that you're only calling readline once, so it only reads one line. If you want to read the lines one by one, you have to keep calling readline in a loop until done:
while True:
msg = fh.readline()
if not msg:
break
msg = msg.split(eqenc)
print(msg)
However, there's really no good reason to call readline here, because any file-like object (including a urlopen object) is already an iterable full of lines, so you can just do this:
for msg in fh:
print(msg)
Meanwhile, your original code has a try without an except or a finally, which will just raise a SyntaxError. Presumably you wanted something like this:
try:
for msg in fh:
print(msg)
except Exception as e:
print('Exception: {}'.format(e))
While we're at it, we can simplify your code a bit.
If you look at the examples:
Here is an example session that uses the GET method to retrieve a URL containing parameters:
That's exactly what you want to do here (except for the last line). All the extra stuff you're doing with encoding the strings is not only unnecessary, but incorrect. UTF-8 is the wrong encoding is the wrong encoding to use for URLs (you get away with it because all of your strings are pure ASCII); urlopen requires a string rather than an encoded byte string (although, at least in CPython 3.0-3.3, it happens to work if you give it byte strings that happen to be encoded properly); urlencode can take byte strings but may not do the right thing (you want to give it the original Unicode so it can quote things properly); etc.
Also, you probably want to decode the result (which is sent as ASCII—for more complicated examples, you'll have to either parse the fh.getheader('Content-Type'), or read the documentation for the API), and strip the newlines.
You also may want to build a structure you can use in your code instead of just printing it out. For example, if you store the results in login_info, and you need the SID in a later request, it's just login_info['SID'].
So, let's wrap things up in a function, then call that function:
import urllib.request
import urllib.parse
def client_login(email, passwd, account_type, service):
params = {'Email': email,
'Passwd': passwd,
'accountType': account_type,
'service': service}
qs = urllib.parse.urlencode(params)
url = 'https://accounts.google.com/ClientLogin?'
with urllib.request.urlopen(url + qs) as fh:
return dict(line.strip().decode('ascii').split('=', 1) for line in fh)
email = 'myemail#stackoverflow.com'
password = 'hidden'
accounttype = 'GOOGLE'
service = 'adwords'
try:
results = client_login(email, password, accounttype, service)
for key, value in results.items():
print('key "{}" is "{}".format(key, value))
except Exception as e:
print('Exception: {}'.format(e))

How can I understand this python error message?

Hi can you help me decode this message and what to do:
main.py", line 1278, in post
message.body = "%s %s/%s/%s" % (msg, host, ad.key().id(), slugify(ad.title.encode('utf-8')))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)
Thanks
UPDATE having tried removing the encode call it appears to work:
class Recommend(webapp.RequestHandler):
def post(self, key):
ad= db.get(db.Key(key))
email = self.request.POST['tip_email']
host = os.environ.get("HTTP_HOST", os.environ["SERVER_NAME"])
senderemail = users.get_current_user().email() if users.get_current_user() else 'info#monton.cl' if host.endswith('.cl') else 'info#monton.com.mx' if host.endswith('.mx') else 'info#montao.com.br' if host.endswith('.br') else 'admin#koolbusiness.com'
message = mail.EmailMessage(sender=senderemail, subject="%s recommends %s" % (self.request.POST['tip_name'], ad.title) )
message.to = email
message.body = "%s %s/%s/%s" % (self.request.POST['tip_msg'],host,ad.key().id(),slugify(ad.title))
message.send()
matched_images=ad.matched_images
count = matched_images.count()
if ad.text:
p = re.compile(r'(www[^ ]*|http://[^ ]*)')
text = p.sub(r'\1',ad.text.replace('http://',''))
else:
text = None
self.response.out.write("Message sent<br>")
path = os.path.join(os.path.dirname(__file__), 'market', 'market_ad_detail.html')
self.response.out.write(template.render(path, {'user_url':users.create_logout_url(self.request.uri) if users.get_current_user() else users.create_login_url(self.request.uri),
'user':users.get_current_user(), 'ad.user':ad.user,'count':count, 'ad':ad, 'matched_images': matched_images,}))
The problem here is your underlying model (message.body) only wants ASCII text but you're trying to give it a string encoded in unicode.
But since you've got a normal ascii string here, you can just make python print out the '?' character when you've got a non-ascii-printing string.
"UNICODE STRING".encode('ascii','replace').decode('ascii')
So like from your example above:
message.body = "%s %s/%s/%s" % \
(msgencode('ascii','replace').decode('ascii'),
hostencode('ascii','replace').decode('ascii'),
ad.key().id()encode('ascii','replace').decode('ascii'),
slugify(ad.title)encode('ascii','replace').decode('ascii'))
Or just encode/decode on the variable that has the unicode character.
But this isn't an optimal solution. The best idea is to make message.body a unicode string. Being that doesn't seem feasible (I'm not familiar with GAE), you can use this to at least not have errors.
You've got a Unicode character in a place that you're not supposed to. Most often I find this error is having MS Word-style slanted quotes.
One of these fields has some characters that cannot be encoded. If you switch to python 3 (it has better unicode support), or you change the encoding of the entire script the problem should stop, about the best way to change the encoding in 2.x is using the encoding comment line. If you see http://evanjones.ca/python-utf8.html you will see more of an explanation of using python with utf-8 support the best suggestion is add # -*- coding: utf-8 -*- to the top of your script. And handle scripts like this
s = "hello normal string"
u = unicode( s, "utf-8" )
backToBytes = u.encode( "utf-8" )
I had a similar problem when using Django norel and Google App Engine.
The problem was at the folder containing the application. Probably isn't this the problem described in this question, but, maybe helps someone don't waste time like me.
Try first change you application folder maybe to /home/ and try to run again, if doesn't works, try something more.

Categories

Resources