I have to admit im very new to this so this might be a dumb question or I might be going around this completely the wrong way. Im trying to figure out the string to sign and Base64 HMAC signature. At this point I would like to verify that the code ive found works. Here it is:
import hashlib
import hmac
import base64
message = bytes("Message").encode('utf-8')
secret = bytes("secret").encode('utf-8')
signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
print(signature)
I had the impression that I could copy the (string to sign) off of the scratchpad and replace it with "Message" and then paste in my secret key for "secret". However my output doesnt match amazon scratchpads signature. Can someone point out the error in my ways?
Related
I am rewriting the codes written in C# with Python. In a part of the C# program, a string is signed with the RSA algorithm and sent to an API.
I have rewritten all parts of the C# program in Python, including the string signature section
The output in the signature of the C# program is the same as the signature of the Python program
But the APi in question does not confirm the signature generated by Python, even though the signature string in C# and Python is exactly the same.
I would be grateful if someone could help me
And whether the output of the RSA algorithm for signature is the same or changes for the same string at each time of encryption (signature)?
In Python, I use the following
from Cryptodome. Signature import pkcs1_15
from Cryptodome. Hash import SHA256
from Cryptodome.PublicKey import RSA
import base64
...
I rewrote the signature of a string that is in C# programming language in Python language (with RSA algorithm and key length of 2048) and it showed me the output of the same string from both programs (C# and Python).
When I send this signature string to an API, it does not receive an error and accepts the signature generated with C#, but it receives an error with the signature generated in Python and does not accept the signature.
What I expected was that since the signature output from both programming languages is the same (the same strings), the desired API should not have any problem with it.
Is my view wrong?
C#
public static string SignData(String stringToBeSigned, string privateKey)
{
var pem = "-----BEGIN PRIVATE KEY-----\n" + privateKey + "\n-----END PRIVATE KEY-----";
PemReader pr = new PemReader(new StringReader(pem));
AsymmetricKeyParameter privateKeyParams = (AsymmetricKeyParameter)pr.ReadObject();
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)privateKeyParams);
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.ImportParameters((RSAParameters)rsaParams);
var dataBytes = Encoding.UTF8.GetBytes(stringToBeSigned);
return Convert.ToBase64String(csp.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
python :
key = RSA.import_key(open('rsa.private').read())
h = SHA256.new(normalize.encode('utf-8'))
signature = pkcs1_15.new(key).sign(h)
base64_bytes = base64.b64encode(signature)
base64_signature = base64_bytes.decode('ascii')
print(base64_signature)
I discovered the Hash-based Message Authentication Code (HMAC) and how to use it with a SHA-256 hash for example.
I follow that link https://pycryptodome.readthedocs.io/en/latest/src/hash/hmac.html.
So I gave it a try and understood how to generate a HMAC, see the snippet below :
mySecret = b"....."
h = HMAC.new(mySecret, digestmod = SHA256)
h.update(b"hello")
print (h.hexdigest()) # 1bef439a8c4fe14770480ebe819cb2e7d5cd68ca4ccf4b3c1f248fc2a525b0a9
Everything is ok on this part.
Then I searched how I could do to reverse it and get mySecret back. And I must admit I have no ideas to make it.
It it possible to do it ?
Thanks.
I know this question has been asked countless times but either the others that asked it were not clear enough or this is simply impossible (nobody said that though), anyway nobody ever gave a clear answer (maybe with the code). So: I am trying to build a cryptocurrency but it's purely for fun so I don't need it to be super-safe and I would have liked to use RSA to verify a user's authenticity, I encrypt the transaction message with the private key and then I send the message along with the encrypted version and then when I need to verify I ask for the public key and decrypt. Now here comes the problem:
apparently it needs the private key to decrypt (which I obviously can't have) while mathematically this would work perfectly without it. Is there any way around this? Something that works similarly but isn't RSA would be fine too.
I found a way with a method as efficient and more secure, here is the code (took directly from the PKCS1_v1_5 documentation):
The following example shows how a private RSA key (loaded from a file) can be used to compute the signature of a message:
>>> from Crypto.Signature import pkcs1_15
>>> from Crypto.Hash import SHA256
>>> from Crypto.PublicKey import RSA
>>>
>>> message = 'To be signed'
>>> key = RSA.import_key(open('private_key.der').read())
>>> h = SHA256.new(message)
>>> signature = pkcs1_15.new(key).sign(h)
At the other end, the receiver can verify the signature (and therefore the authenticity of the message) using the matching public RSA key:
>>> key = RSA.import_key(open('public_key.der').read())
>>> h = SHA.new(message)
>>> try:
>>> pkcs1_15.new(key).verify(h, signature)
>>> print "The signature is valid."
>>> except (ValueError, TypeError):
>>> print "The signature is not valid."
Hopefully this will be helpful if not here is the link for the page itself: https://pycryptodome.readthedocs.io/en/latest/src/signature/pkcs1_v1_5.html
I am trying to create a token for an API call in R. I have example code and output in Python, but I am unable to replicate in R. I know little to nothing about encoding, decoding, etc. Hoping someone can shed some light on what I can do to make these outputs match. Here is a toy example.
R Code:
library(RCurl)
library(digest)
api_key = "abcdefghijklmnopqrstuvwxyz123456789=="
decoded_api_key = base64Decode(api_key)
hmac_binary = hmac(decoded_api_key, "MySpecialString", "sha512")
hmac_encoded = base64Encode(digest(hmac_binary))
print(as.character(hmac_encoded))
# ZmZjZDBlMjkyNzg3NDNmYWM1ZDcyNjVkNmY4ZmM1OGQ=
Python:
import hmac
import hashlib
import base64
api_key = "abcdefghijklmnopqrstuvwxyz123456789=="
decoded_api_key = base64.b64decode(api_key)
hmac_binary = hmac.new(decoded_api_key, "MySpecialString", hashlib.sha512)
hmac_encoded = base64.b64encode(hmac_binary.digest())
print(hmac_encoded)
# MduxNfXVkwcOtCpBWJEl96S43boYVYTtHb4waR21ARCMo6iokKuxbwEJMTkuytbrCOxvBqKCYiaZiV/AyHTEcw==
The answers I obtain are given at the end of the code blocks. Clearly they don't match. I'd like someone to help me change my R code to match the Python output.
Thanks in advance.
The digest() function in R doesn't do the same thing as the .digest() method in python. It doesn't extract the value, it computes a new digest for whatever you pass in. Also the hmac function will by default return a string with the bytes in it, but you want to base64 encode the actual bytes so you need to make sure to request the raw values. Finally, a base64 string should have a multiple of 4 characters in the string. The extra padding seems to return a different value. So this should give the same value as the python code
api_key = "abcdefghijklmnopqrstuvwxyz123456789="
decoded_api_key = base64Decode(api_key)
hmac_binary = hmac(decoded_api_key, "MySpecialString", "sha512", raw=TRUE)
hmac_encoded = base64Encode(hmac_binary)
print(as.character(hmac_encoded))
# [1] "MduxNfXVkwcOtCpBWJEl96S43boYVYTtHb4waR21ARCMo6iokKuxbwEJMTkuytbrCOxvBqKCYiaZiV/AyHTEcw=="
I'm following the directions on the API documentation precisely, and after some frustration I finally put together something directly from their examples on http://docs.amazonwebservices.com/AWSECommerceService/2011-08-01/DG/rest-signature.html
I've tried this python script on a few machines and have gotten the same result on all of them.
import hmac
from base64 import b64encode
from hashlib import sha256
secret_key = '1234567890'
to_sign = """GET
webservices.amazon.com
/onca/xml
AWSAccessKeyId=AKIAI44QH8DHBEXAMPLE&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=ItemAttributes%2COffers%2CImages%2CReviews&Service=AWSECommerceService&Timestamp=2009-01-01T12%3A00%3A00Z&Version=2009-01-06"""
print b64encode(hmac.new(secret_key, to_sign, sha256).digest())
The instructions say that the signature using this request, and this key, is Nace+U3Az4OhN7tISqgs1vdLBHBEijWcBeCqL5xN9xg= but I get O6UTkH+m4zAQUvB+WXUZJeA8bZcKAdkc4crKgHtbc6s=
(Before anyone says anything: The example page displays the requests wrapped at 65 characters; I've already tried it. This doesn't provide a solution, and is not stated in the instructions for signature creation.)
EDIT: I found the answer, see below.
Well, look at that... The docs were wrong.
I stumbled on an old (nearly) duplicate of this question: Calculating a SHA hash with a string + secret key in python
It looks like the AWSAccessKeyId value changed from 00000000000000000000 to AKIAI44QH8DHBEXAMPLE in the example requests page.
Updating this in the script prints the expected key, Nace+U3Az4OhN7tISqgs1vdLBHBEijWcBeCqL5xN9xg=
import hmac
from base64 import b64encode
from hashlib import sha256
secret_key = '1234567890'
to_sign = """GET
webservices.amazon.com
/onca/xml
AWSAccessKeyId=00000000000000000000&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=ItemAttributes%2COffers%2CImages%2CReviews&Service=AWSECommerceService&Timestamp=2009-01-01T12%3A00%3A00Z&Version=2009-01-06"""
print b64encode(hmac.new(secret_key, to_sign, sha256).digest())
You might check out the Bottlenose library, https://github.com/dlo/bottlenose, I have found that it makes dealing with AWS Product API much more friendly.