Python HMAC hashed value encoding to base64 - python

I am trying to make a twitter auth with the help of django middleware, where I calculate the signature of a request like this (https://dev.twitter.com/oauth/overview/creating-signatures):
key = b"MY_KEY&"
raw_init = "POST" + "&" + quote("https://api.twitter.com/1.1/oauth/request_token", safe='')
raw_params = <some_params>
raw_params = quote(raw_params, safe='')
#byte encoding for HMAC, otherwise it returns "expected bytes or bytearray, but got 'str'"
raw_final = bytes(raw_init + "&" + raw_params, encoding='utf-8')
hashed = hmac.new(key, raw_final, sha1)
request.raw_final = hashed
# here are my problems: I need a base64 encoded string, but get the error "'bytes' object has no attribute 'encode'"
request.auth_header = hashed.digest().encode("base64").rstrip('\n')
As you can see, there is no way to base64 encode a 'bytes' object.
The proposed solution was here: Implementaion HMAC-SHA1 in python

The trick is to use base64 module directly instead of str/byte encoding, which supports binary.
You can fit it like this (untested in your context, should work):
import base64
#byte encoding for HMAC, otherwise it returns "expected bytes or bytearray, but got 'str'"
raw_final = bytes(raw_init + "&" + raw_params, encoding='utf-8')
hashed = hmac.new(key, raw_final, sha1)
request.raw_final = hashed
# here directly use base64 module, and since it returns bytes, just decode it
request.auth_header = base64.b64encode(hashed.digest()).decode()
For test purposes, find below a standalone, working example (python 3 compatible, Python 2.x users have to remove the "ascii" parameter when creating the bytes string.):
from hashlib import sha1
import hmac
import base64
# key = CONSUMER_SECRET& #If you dont have a token yet
key = bytes("CONSUMER_SECRET&TOKEN_SECRET","ascii")
# The Base String as specified here:
raw = bytes("BASE_STRING","ascii") # as specified by oauth
hashed = hmac.new(key, raw, sha1)
print(base64.b64encode(hashed.digest()).decode())
result:
Rh3xUffks487KzXXTc3n7+Hna6o=
PS: the answer you linked to does not work anymore with Python 3. It's python 2 only.

Just thought I'd adjust the answer for Python3.
from hashlib import sha512
import hmac
import base64
key = b"KEY"
path = b"WHAT YOU WANT TO BE SIGNED"
hashed = hmac.new(key, path, sha512).digest()
print(base64.b64encode(hashed))

Related

RabbitMQ password hashing in NodeJS

I am using RabbitMQ with Docker. I would like to update the configurations directly in the definitions.json file. The users should have their password stored there with rabbit_password_hashing_sha256 hashing algorithm. I have found a useful Python script for hashing the password but I was not able to reproduce it's logic in NodeJS with Crypto library.
Python script:
#!/usr/bin/env python3
# RabbitMQ password hashing algorith as laid out in:
# http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2011-May/012765.html
from __future__ import print_function
import base64
import os
import hashlib
import struct
import sys
# The plain password to encode
password = sys.argv[1]
# Generate a random 32 bit salt
salt = os.urandom(4)
# Concatenate with the UTF-8 representation of plaintext password
tmp0 = salt + password.encode('utf-8')
# Take the SHA256 hash and get the bytes back
tmp1 = hashlib.sha256(tmp0).digest()
# Concatenate the salt again
salted_hash = salt + tmp1
# Convert to base64 encoding
pass_hash = base64.b64encode(salted_hash)
# Print to the console (stdout)
print(pass_hash.decode("utf-8"))
Output: python hash-password.py test >> t7+JG/ovWbTd9lfrYrPXdFhNZLcO+y56x4z0d8S2OutE6XTE
First implementation failure:
const crypto = require('crypto');
this.password = process.argv[2];
this.salt = crypto.randomBytes(16).toString('hex');
this.password_hash = crypto.pbkdf2Sync(this.password.trim(), this.salt, 1000, 24, `sha256`).toString(`hex`);
console.log(this.password_hash);
Output: node password.js test >> 7611058fb147f5e7a0faab8a806f56f047c1a091d8355544
I was not able to reproduce it in NodeJS, so I collected the stdout result of the executed child process, which is not too elegant.
Second implementation failure:
const crypto = require('crypto');
const utf8 = require('utf8');
this.password = process.argv[2];
this.salt = crypto.randomBytes(4);
this.tmp0 = this.salt + utf8.encode(this.password);
this.tmp1 = crypto.createHash(`sha256`).digest();
this.salted_hash = this.salt + this.tmp1;
this.pass_hash = Buffer.from(this.salted_hash).toString('base64');
console.log(utf8.decode(this.pass_hash));
Output: node password.js test >> Mu+/ve+/vWnvv73vv71C77+977+9HBTvv73vv73vv73ImW/vv70kJ++/vUHvv71k77+977+9TO+/ve+/ve+/vRt4Uu+/vVU=
Can anyone help with the right implementation?
You can do the port to NodeJS more or less 1:1:
var crypto = require('crypto')
// The plain password to encode
var password = Buffer.from('my passphrase', 'utf8') // sample password
// Generate a random 32 bit salt
var salt = crypto.randomBytes(4);
//var salt = Buffer.from('1234', 'utf8'); // for testing, gives pass_hash = MTIzNNcAIpZVAOz2It9VMePU/k4wequLpsQVl+aYDdJa6y9r
// Concatenate with the UTF-8 representation of plaintext password
var tmp0 = Buffer.concat([salt, password])
// Take the SHA256 hash and get the bytes back
var tmp1 = crypto.createHash('sha256').update(tmp0).digest()
// Concatenate the salt again
var salted_hash = Buffer.concat([salt, tmp1])
// Convert to base64 encoding
pass_hash = salted_hash.toString('base64')
// Print to the console (stdout)
console.log(pass_hash)
The code above uses as example password my passphrase. You need to replace the password with yours.
Note that even if the passwords are identical, you cannot directly compare the results of Python and NodeJS code because of the random salt.
Therefore, the commented out line with the UTF-8 encoded salt 1234 can be used to produce a result for comparison with the Python code: MTIzNNcAIpZVAOz2It9VMePU/k4wequLpsQVl+aYDdJa6y9r
The issue in your first implementation is, among other things, the use of PBKDF2, which is not applied in the Python code.
The second implementation is closer to the actual solution. One problem is that the hashing does not take into account the data to be hashed.
Another defect is the use of strings, where some operations implicitly apply UTF-8 encoding, which corrupts the (arbitrary binary) data. To prevent this, binary must be used as encoding instead of UTF-8. Just because of the possible encoding issues, the implementation with strings is less robust here than with buffers.

Matching Signing between Python and Ruby

I have been trying for a few days to validate some message signed with a private key in python. Note that the message has been signed using Ruby.
When I sign the same message in python I can verify it no problem. Note that I have already validated that the hash are the same.
Python code:
string_to_encrypt = b"aaaaabbbbbaaaaabbbbbaaaaabbbbbCC"
sha1 = SHA.new()
sha1.update(string_to_encrypt)
# load private key
pkey = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, open('./license.pem', 'rb').read())
sign_ssl = OpenSSL.crypto.sign(pkey, sha1.digest(), 'RSA-SHA1')
b64_ssl = base64.b64encode(sign_ssl)
Ruby:
string_to_encrypt = "aaaaabbbbbaaaaabbbbbaaaaabbbbbCC"
sha1 = Digest::SHA1.digest(string_to_encrypt)
#sign it
private_key_file = File.join(File.dirname(__FILE__), 'license.pem')
rsa = OpenSSL::PKey::RSA.new(File.read(private_key_file))
signed_key = rsa.private_encrypt(sha1)
#update the license string with it
x = Base64.strict_encode64(signed_key)
I would expect b64_ssl and x to contain the same value and they don't. Could someone explain to me what I missing there?
Neither of these code snippets is actually producing the correct signature.
In the Ruby OpenSSL library you want to be using the sign method, not the private_encrypt method, which is a low level operation that doesn’t do everything required to produce a valid signature.
In both libraries the sign operation performs the hashing for you, you don’t need to do this beforehand. In fact your Python code is actually hashing the data twice.
Try the following Python code:
import OpenSSL
import base64
string_to_encrypt = b"aaaaabbbbbaaaaabbbbbaaaaabbbbbCC"
# load private key
pkey = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, open('./license.pem', 'rb').read())
sign_ssl = OpenSSL.crypto.sign(pkey, string_to_encrypt, 'SHA1')
b64_ssl = base64.b64encode(sign_ssl)
print(b64_ssl.decode())
which produces the same output as this Ruby code:
require 'openssl'
require 'base64'
string_to_encrypt = "aaaaabbbbbaaaaabbbbbaaaaabbbbbCC"
#sign it
private_key_file = File.join(File.dirname(__FILE__), 'license.pem')
rsa = OpenSSL::PKey::RSA.new(File.read(private_key_file))
signed_key = rsa.sign('sha1', string_to_encrypt)
#update the license string with it
x = Base64.strict_encode64(signed_key)
puts x

AES key moved in config file generate " AES key must be either 16, 24, or 32 bytes long" error

I'm using python,flask.I'm doing encryption with AES. It works good, I encrypt and decrypt data easly .
To secure the encryption key i moved my encryption key from app form in config file. First I saved a variable in a config file,I declared ENCRYPTION_KEY in config.cfg .
[Encryption]
ENCRYPTION_KEY = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'
and then on init file i declared:
app.config['ENCRYPTION_KEY'] = config.get('Encryption', 'ENCRYPTION_KEY')
I tried accessing it from key = flask.config['ENCRYPTION_KEY']. I print key in console just to be sure that the command works:
def encrypt_data(self, form_data):
key = current_app.config['ENCRYPTION_KEY']
print "KEY : " , key
cipher = AES.new(key)
//code...
And in console key is printed:
Now when i try to use this key from config file,i have an error message:
This message appears only because i moved that key in config file, because as I said before i used the same key for the same methods and it works perfectly?
Can anybody help me, why I'm getting this error?
Your use of the ConfigParser module is the cause of the problem. Given the config file shown:
>>> config.get('Encryption', 'ENCRYPTION_KEY')
"b'\\xbf\\xc0\\x85)\\x10nc\\x94\\x02)j\\xdf\\xcb\\xc4\\x94\\x9d(\\x9e[EX\\xc8\\xd5\\xbfI{\\xa2$\\x05(\\xd5\\x18'"
>>> len(config.get('Encryption', 'ENCRYPTION_KEY'))
92
you can see here that ConfigParser simply returns the value associated with the given config variable as text, not as a Python string. Because the config value contains backslash escape sequences, these backslashes are escaped with additional backslashes. This breaks the \x character sequences which then blow out to 4 characters.
The easiest way around this is to use Flask's config files:
config.cfg
ENCRYPTION_KEY = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'
>>> import flask
>>> app = flask.Flask('test')
>>> app = flask.Flask('')
>>> app.config.from_pyfile('config.cfg')
True
>>> app.config['ENCRYPTION_KEY']
'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'
>>> len(app.config['ENCRYPTION_KEY'])
32
If you do not want to use Flask's config files your options are (in order of preference):
Use ast.literal_eval() to safely convert the raw string into a Python string:
from ast import literal_eval
app.config['ENCRYPTION_KEY'] = literal_eval(config.get('Encryption', 'ENCRYPTION_KEY'))
Base64 encode the value in the config file, e.g.
[Encryption]
ENCRYPTION_KEY = v8CFKRBuY5QCKWrfy8SUnSieW0VYyNW/SXuiJAUo1Rg=
Then decode it when you access the key:
app.config['ENCRYPTION_KEY'] = config.get('Encryption', 'ENCRYPTION_KEY').decode('base64')
Use eval() to convert the raw string into a Python string:
app.config['ENCRYPTION_KEY'] = eval(config.get('Encryption', 'ENCRYPTION_KEY'))
although this is considered bad/dangerous practice and you would be better off using literal_eval() or base64 encoding.
Store the key as a binary value in the file: [Encryption]
ENCRYPTION_KEY = ¿À<85>)^Pnc<94>^B)jßËÄ<94><9d>(<9e>[EXÈÕ¿I{¢$^E(Õ^X
but that is very difficult to maintain.

Base64 decoding and writing to file in Python sending Base64-String over cgi.Fieldstorage

I want to safe an image file to a server folder.
I recive the image over cgi.Fieldstorage. The adress and Base64 String looks like this:
http://localhost/upload.py?data={"base64" : "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"}
As far as I found out Python uses the Standard 'Base64' encoding for RFC 3548 or RFC 4648, so the String should be alright.
I try this code:
def getParam():
import json
import cgi
form3 = cgi.FieldStorage()
form2 = form3["data"].value
form1 =json.loads(form2)
return(form1)
a = getParam()
import base64
print(a["base64"])
imgdata = base64.b64decode(a["base64"])
print("----------------------------------------------")
print(imgdata)
filename = '/var/www/images/some_image.jpg'
t = open(filename, "wb")
t.write(base64.b64decode(a["base64"]))
t.close()
print(filename)
the response if I execute is
/9j/4AAQSkZJRgABAQEAYABgAAD/4QEMRXhpZgAATU0AKgAAAAgAAYdpAAQAAAABAAAAFgABkoYABwAAAOAAAAAkVU5JQ09ERQAASQBtAGEAZwBlACAAbABpAGMAZQBuAHMAZQBkACAAdABvACAAWgBhAHoAegBsAGUAIABJAG4AYwAuACAAQQBsAGwAIAB1AG4AYQB1AHQAaABvAHIAaQB6AGUAZAAgAHUAcwBlACAAaQBzACAAcAByAG8AaABpAGIAaQB0AGUAZAAuACAAZABlADAANgA0ADgAYgA0AC0ANwA4AGYAYgAtADQANQBkADIALQA4ADcANgBiAC0AZABkADYAOQA4ADgAYQAwADcAMgA4ADAAAAAAAAAAAAAAAAD/2wBDAAQDAwQDAwQEAwQFBAQFBgoHBgYGBg0JCggKDw0QEA8NDw4RExgUERIXEg4PFRwVFxkZGxsbEBQdHx0aHxgaGxr/2wBDAQQFBQYFBgwHBwwaEQ8RGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhr/wAARCAAyADIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4 Tl5ufo6erx8vP09fb3 Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3 Pn6/9oADAMBAAIRAxEAPwD7 orj7Y6tqk19Kut3NpHHeTQpFFBCVVUcqOWQnt61S8TX154W0K91bUPEl/5FrGXKi3tsseyj931J4qZSUIuUnZIqMXJqK3Z3tFeJ3/xF1CDwTZ JtP1DVrwXGWa18m2V40U4dj 6PAyPzFdnoN1deJNItNU0vxRfS2t1GHQ/Z7bI9Qf3fBB4NYU8TRqy5ISu7J/J9TSdCpTjzSWl7fM7miuX/s3Vv hkvv8AwHtv/jdV9QttYsrG5uE8RXjtDEzhWt7fBIGcHEftXSYnYUVHbyGW3ikb7zoGP1IooA8Y134vaN4C1y20rVHw9/q9wszHgQxtIwEhPTAYDIOODntTPi5rPgvW7RdH8SeNrPQIbWdXuleQAMf4VYkgDkisjxX8FIviN4oOo6jevHpsF9dedAjEOxEjYC9gM47E9eeAK O9fvrWHWNbsfE8M012moNvjktyY0mi cQ7iNpbKk7T64xXzePxFem3TqU aEn57K19v1PZ4fwUsZVryrVFDltyapXbT730uuivqfROkePF8L Jp7uGWPVtFt/NhggSQNH5LbV3KRkNlI48duPevpjwvPpd1odpN4eihg0 Vd6RwqFVCeSMDgHJOfevzdvNJ11tHsbfw9eQ6Lc20iOCowuF/hIGQRnmvZvh5 0Fr3gbTY9P16Oz1iMSN5kxX7OxKqoZuPlHI6Ae/UmvJyzMqWHcvazum3ZWu0fT43h3HVkuWnZpLdpJ/ifalUNb/wCQNqH/AF7Sf gmvK/C37Sfg3xCkIu5J9LmkjWQLMmV2t0O4dvriu m8T6PrmiXzaRqdpeBreTAimDH7p7V9hSxeHr/AMOaf5/cfH4jL8Xhf41Npd7affsddZf8edv/ANcl/lRSWBzY23/XJP5Ciuo885ezum0qW/gu7O LNezyqYrOSVSruWUhlBHQ/hXkV/8AA7QL/wAet4jlu/ER02XVV1ifRW0p2t5LwAfPkpnaSoJXnPPrX0bRSaT3Gm1qjyu78F CL0kz EJMnqU0iZP/AEFRXG M/gb4G8T6M1np iXuk3QmWZLj yJ7hcjgq0bDDKQenHOD2r6GornWFw6lzKCv6I7Hj8XKDg6srPpd2/M8H0D4QfD/AEHS9PtJfDeoXk9raRW8lw n3QM2xcbioGBnk47Zrcbw14PsbaX x/Cs8N6sbeQ40ifcHwcYYrxXrlFCwuHi ZU1f0Q5Y/GSjySqya7cz/zK1jHJFY20ci4dIlVh7gCirNFdJwhRRRQAUUUUAFFFFABRRRQB/9k=
----------------------------------------------
b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00\xff\xe1\x01\x0cExif\x00\x00MM\x00*\x00\x00\x00\x08\x00\x01\x87i\x00\x04\x00\x00\x00\x01\x00\x00\x00\x16\x00\x01\x92\x86\x00\x07\x00\x00\x00\xe0\x00\x00\x00$UNICODE\x00\x00I\x00m\x00a\x00g\x00e\x00 \x00l\x00i\x00c\x00e\x00n\x00s\x00e\x00d\x00 \x00t\x00o\x00 \x00Z\x00a\x00z\x00z\x00l\x00e\x00 \x00I\x00n\x00c\x00.\x00 \x00A\x00l\x00l\x00 \x00u\x00n\x00a\x00u\x00t\x00h\x00o\x00r\x00i\x00z\x00e\x00d\x00 \x00u\x00s\x00e\x00 \x00i\x00s\x00 \x00p\x00r\x00o\x00h\x00i\x00b\x00i\x00t\x00e\x00d\x00.\x00 \x00d\x00e\x000\x006\x004\x008\x00b\x004\x00-\x007\x008\x00f\x00b\x00-\x004\x005\x00d\x002\x00-\x008\x007\x006\x00b\x00-\x00d\x00d\x006\x009\x008\x008\x00a\x000\x007\x002\x008\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xdb\x00C\x00\x04\x03\x03\x04\x03\x03\x04\x04\x03\x04\x05\x04\x04\x05\x06\n\x07\x06\x06\x06\x06\r\t\n\x08\n\x0f\r\x10\x10\x0f\r\x0f\x0e\x11\x13\x18\x14\x11\x12\x17\x12\x0e\x0f\x15\x1c\x15\x17\x19\x19\x1b\x1b\x1b\x10\x14\x1d\x1f\x1d\x1a\x1f\x18\x1a\x1b\x1a\xff\xdb\x00C\x01\x04\x05\x05\x06\x05\x06\x0c\x07\x07\x0c\x1a\x11\x0f\x11\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\xff\xc0\x00\x11\x08\x002\x002\x03\x01"\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01}\x01\x02\x03\x00\x04\x11\x05\x12!1A\x06\x13Qa\x07"q\x142\x81\x91\xa1\x08#B\xb1\xc1\x15R\xd1\xf0$3br\x82\t\n\x16\x17\x18\x19\x1a%&\'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe19y\xb9\xfa:z\xbc|\xbc\xfd=}\xbd\xcf\x9f\xaf\xfc#\x01\xf0\x10\x000\x10\x10\x10\x10\x10\x10\x10\x10\x10\x00\x00\x00\x00\x00\x00\x10 0#P`p\x80\x90\xa0\xbf\xfc#\x0bQ\x10\x00 \x10 ##0#pP##\x00\x10\'p\x00\x10 1\x10#R\x13\x10a$\x15\x10v\x17\x112#(\x10\x81D)\x1a\x1b\x1c\x10\x9235/\x01V\'-\x10\xa1bCN\x12_\x11q\x81\x91\xa2br\x82\x92\xa3Scs\x83\x93\xa44DTdt\x84\x94\xa55EUeu\x85\x95\xa66FVfv\x86\x96\xa77GWgw\x87\x97\xa8(8HXhx\x88\x98\xa9)9IYiy\x89\x99\xaa*:JZjz\x8a\x9a\xab+;K[k{\x8b\x9b\xac,<L\\l|\x8c\x9c\xad-=M]m}\x8d\x9d\xae.>N^n~\x8e\x9e\xaf/?O_os\xe7\xeb\xffh\x000\x0c\x04\x00\x08D\x0cD\x00\xfc\x03\xee\x8a\xe3\xed\x8e\xad\xaaM}*\xebw6\x91\xc7y4)\x14PBUU\x1c\xa8\xe5\x90\x9e\xde\xb5K\xc4\xd7\xd7\x9e\x16\xd0\xafumC\xc4\x97\xfeE\xace\xca\x8b{l\xb1\xec\xa3\xf7}I\xe2\xa6RP\x8b\x94\x9d\x92*1rj+vw\xb4W\x89\xdf\xfcE\xd4 \xf0M\x92m?P\xd5\xaf\x05\xc6Y\xad|\x9bex\xd1N\x1d\x8f\xa3\xc0\xc8\xfc\xc5vz\r\xd5\xd7\x894\x8bMSK\xf1E\xf4\xb6\xb7Q\x87C\xf6{l\x8fP\x7fw\xc1\x07\x83XS\xc4\xd1\xab.HJ\xee\xc9\xfc\x9fSI\xd0\xa9N<\xd2Z^\xdf3\xb9\xa2\xb9\x7f\xec\xdd[\xe1\x92\xfb\xfc\x03\x01\xed\xbf\xf8\xddW\xd4-\xb5\x8b+\x1b\x9b\x84\xf1\x15\xe3\xb413\x85k{|\x12\x06pq\x1f\xb5t\x98\x9d\x85\x15\x1d\xbc\x86[x\xa4o\xbc\xe8\x18\xfdH\xa2\x80<c]\xf8\xbd\xa3x\x0b\\\xb6\xd2\xb5G\xc3\xdf\xea\xf7\x0b3\x1e\x041\xb4\x8c\x04\x84\xf4\xc0`2\x0e89\xedL\xf8\xb9\xac\xf8/[\xb4]\x1f\xc4\x9e6\xb3\xd0!\xb5\x9d^\xe9^#\x03\x1f\xe1V$\x809"\xb2<W\xf0R/\x88\xde(:\x8e\xa3z\xf1\xe9\xb0_]y\xd0#\x10\xecD\x8d\x80\xbd\x80\xce;\x13\xd7\x9e\x00\xa3\xbd~\xfa\xd6\x1dc[\xb1\xf1<3Mv\x9a\x83o\x8eKrcI\xa2q\x0e\xe26\x96\xca\x93\xb4\xfa\xe3\x15\xf3x\xfcEzm\xd3\xa9F\x84\x9f\x9e\xca\xd7\xdb\xf5=\x9e\x1f\xc1K\x19V\xbc\xabTP\xe5\xb7&\xa9]\xb4\xfb\xdfK\xae\x8a\xfa\x9fD\xe9\x1e<_\x0b&\x9e\xee\x19c\xd5\xb4[\x7f6\x18 I\x03G\xe4\xb6\xd5\xdc\xa4d6R8\xf1\xdb\x8fz\xfac\xc2\xf3\xe9wZ\x1d\xa4\xde\x1e\x8a\x184U\xde\x91\xc2\xa1U\t\xe4\x8c\x0e\x01\xc99\xf7\xaf\xcd\xdb\xcd\']m\x1e\xc6\xdf\xc3\xd7\x90\xe8\xb76\xd2#\x82\xa3\x0b\x85\xfe\x12\x06A\x19\xe6\xbd\x9b\xe1\xe7Ak\xde\x06\xd3c\xd3\xf5\xe8\xec\xf5\x88\xc4\x8d\xe6LW\xec\xecJ\xaa\x86n>Q\xc8\xe8\x07\xbfRk\xc9\xcb3*Xw/k;\xa6\xdd\x95\xae\xd1\xf4\xf8\xde\x1d\xc7VK\x96\x9d\x9aKv\x92\x7f\x89\xf6\xa5P\xd6\xff\xc0$\r\xa8\x7f\xc0\x17\xb4\x9f\x82k\xca\xfc-\xfbI\xf87\xc4)\x08\xbb\x92}.i#Y\x02\xcc\x99]\xad\xd0\xee\x1d\xbe\xb8\xae\x9b\xc4\xfa>\xb9\xa2_6\x91\xa9\xda^\x06\xb7\x93\x02)\x83\x1f\xba{W\xd8R\xc5\xe1\xeb\xfc\x03\x0ei\xfe\x7fq\xf1\xf8\x8c\xbf\x17\x85\xfe56\x97{i\xf7\xecu\xd6_\xf1\xe7o\xfc\x03\\\x97\xf9QI`scm\xff\\\x93\xf9\n+\xa8\xf3\xce^\xce\xe9\xb4\xa9o\xe0\xbb\xb3\x8b5\xec\xf2\xa9\x8a\xceIT\xab\xb9e!\x94\x11\xd0\xfe\x15\xe4W\xff\x00\x03\xb4\x0b\xff\x00\x1e\xb7\x88\xe5\xbb\xf1\x11\xd3e\xd5WX\x9fEm)\xda\xdeK\xc0\x07\xcf\x92\x99\xdaJ\x82W\x9c\xf3\xeb_F\xd1I\xa4\xf7\x1amj\x8f+\xbb\xf0P\x8b\xd2L\xc4$\xc9\xeaSH\x99?\xf0\x04\x15\x15\xc63\xf8\x1b\xe0o\x13\xe8\xcdg\xa6%\xee\x93t&Y\x92\xe3\xc8\x9e\xe1r8*\xd1\xb0\xc3)\x07\xa7\x1c\xe0\xf6\xaf\xa1\xa8\xaeu\x85\xc3\xa9s(+\xfa#\xb1\xe3\xf1r\x83\x83\xab+>\x97v\xfc\xcf\x07\xd0>\x10|?\xc0\x10t\xbd>\xd2_\r\xea\x17\x93\xda\xdaEo%\xc2}\xd03l\\n*\x06\x06y8\xed\x9a\xdco\rx>\xc6\xda_\x1f\xc2\xb3\xc3z\xb1\xb7\x90\xe3H\x9fp|\x1ca\x8a\xf1^\xb9E\x0b\x0b\x87\x89\x955\x7fD9c\xf1\x92\x8f$\xaa\xc9\xae\xdc\xcf\xfc\xca\xd61\xc9\x15\x8d\xb4r.\x1d"Ua\xee\x00\xa2\xac\xd1]\'\x08QE\x14\x00QE\x14\x00QE\x14\x00QE\x14\x01\xff\xd9'
/var/www/images/some_image.jpg
Problem is I can't open the file generated this way (Unsupported marker type 0x68). Why?
Edit: I just recognized that after the String is loaded + is replaced with
If you hand over data via adress bar, + is automatically converted to an empty space. Just string.replace(' ', '+') on the Base64-String and you should be fine.

Ruby HMAC-SHA Differs from Python

I'm rewriting some existing code from Python to Ruby, and I've across a strange error that I can't seem to figure out. Here we have the Python code (which works):
import sha, hmac
data = 'sampledata'
data = data.encode('ascii')
des_key = hmac.new(data + "\0", "SUPERSECRET", sha).digest()[0:8]
Output: 0x64F461D377D9930C
And the Ruby (which I'm new to) code:
require 'openssl'
digest = OpenSSL::Digest::SHA.new
data = 'sampledata'
data.encode!('ascii')
puts OpenSSL::HMAC.hexdigest(digest, "SUPERSECRET", data + "\0")[0, 16]
Output: 0x563FDAF11E63277C
What could be causing this difference?
You made two mistakes:
Python's hmac.new takes key, method, digest - so you should write
hmac.new("SUPERSECRET",data + "\0", sha)
The default digest method for OpenSSL::Digest in Ruby isn't SHA1 (I'm not sure what it is). You should just use:
OpenSSL::HMAC.hexdigest('sha1',"SUPERSECRET",data+"\0")[0,16]
Both methods (first in Python, second in Ruby) return the same output.
In addition to Guy Adini's answer - in Ruby SHA is different from python sha which is sha1 (in sha.py: from hashlib import sha1 as sha):
from hashlib import *
import hmac
data = 'sampledata'
data = data.encode('ascii')
algo = [sha1, sha224, sha256, sha512]
for al in algo:
print al().name, hmac.new("SUPERSECRET", data + "\0", al).hexdigest()[0:16]
produces:
sha1 50c61ea49195f03c
sha224 fd6a418ee0ae21c8
sha256 79deab13bd7b041a
sha512 31561f9c9df69ab2
and in Ruby:
require 'openssl'
data = 'sampledata'
data.encode!('ascii')
%w(sha sha1 sha224 sha256 sha512).each do |al|
puts "#{al}: #{OpenSSL::HMAC::hexdigest(al, "SUPERSECRET", "#{data}\0")[0,16]}"
end
produces:
sha: 563fdaf11e63277c
sha1: 50c61ea49195f03c
sha224: fd6a418ee0ae21c8
sha256: 79deab13bd7b041a
sha512: 31561f9c9df69ab2

Categories

Resources