CryptoPro pycades.SignedData.Verifycades() - python

I have a sign and signed data. By using them I have to verify a sign. To do it I use CryptoPro's extension for Python (pycades)
I wrote such code:
import sys
import base64
sys.path.append("/home/mevarg10rg1/Desktop/derzTest/cprocsp/pycades_0.1.30636")
import pycades
sign=open("/home/mevarg10rg1/Desktop/derzTest/file_signed.sig","r").read()
data=open("/home/mevarg10rg1/Desktop/derzTest/base64","r").read()
data=data.replace(chr(0),"")
signedData=pycades.SignedData()
signedData.ContentEncoding=pycades.CADESCOM_BASE64_TO_BINARY
signedData.Content=data
_signedData=pycades.SignedData()
_signedData.ContentEncoding=pycades.CADESCOM_BASE64_TO_BINARY
_signedData.Content=signedData.Content
_signedData.VerifyCades(sign,pycades.CADESCOM_CADES_BES,True)
But got Exception:Invalid Signature (0x80090006)
Sign is valid, I am sure

Related

different utf8 encoding outputs between Python and Haskell

I'm trying to encode a has which is computed by hmac sha256 in Haskell and sometimes my function has different output when compared to it's Python counterpart.
This is the python funciton:
import requests
import json
import hmac
import hashlib
import base64
import time
def strToSign(time, method, endpoint, body):
return time + method + endpoint + body
str_to_sign2 = strToSign('1','GET','/api/v1/position?symbol=XBTUSDM','')
signature2 = base64.b64encode(
hmac.new(api_secret.encode('utf-8'), str_to_sign2.encode('utf-8'), hashlib.sha256).digest())
And this is the Haskell function:
import qualified Data.ByteString.Char8 as BC
import qualified Data.Text as T
import qualified Data.ByteString.Base64.URL as U
import Data.Text.Encoding (encodeUtf8)
import qualified Crypto.Hash.SHA256 as H
apiSignTest :: BC.ByteString -> BC.ByteString -> BC.ByteString -> BC.ByteString -> IO BC.ByteString
apiSignTest time method endpoint body = do
let timeStamp = time
let secret = mconcat [timeStamp,method,endpoint,body]
let hash = H.hmac (BC.pack C.apiSecretFuture) secret
return $ (encodeUtf8 . U.encodeBase64) hash
some examples where the encoded outputs are different
Haskell : b'KbCFw8OYGeGB433L93vQvbsnzSXxG88r_-HR5AGDJmo='
Python : "KbCFw8OYGeGB433L93vQvbsnzSXxG88r/+HR5AGDJmo="
Python : b'dwSmCd75wZToIDt6I0Ik/sX8Vxk4W+RA0Sv1TO+x4WI='
Haskell : "dwSmCd75wZToIDt6I0Ik_sX8Vxk4W-RA0Sv1TO-x4WI="
Python : b'X8SE3ohju6VAu2Dt5nGIQP40+KU9RrhXORAUOdL7rJg='
Haskell : "X8SE3ohju6VAu2Dt5nGIQP40-KU9RrhXORAUOdL7rJg="
Data.ByteString.Base64.URL.encodeBase64 is specifically using the base64url encoding rather than vanilla base64. The purpose, as the name suggests, is that these encodings can be directly embedded in URLs, which the vanilla version cannot because / and + have special meanings in URLs.
To get the same behaviour as Python's b64encode, use Data.ByteString.Base64.encodeBase64 instead. Or, the other way around, in Python you can use urlsafe_b64encode.

RSA sign a string with private key in python

I am communicating with our clients server. For an api I need to sign a string with my private key. They have the following condition to follow
User SHA 256 algorithm to calculate the hash of the string
Use the private key and RSA (PKCS1_PADDING) algorithm to sign the Hash Value.
Base64 encode the encrypted Hash Value
and I am doing following
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
import base64
pkey = RSA.importKey(keystring)
message = "Hello world"
h = SHA256.new(message.encode())
signature = PKCS1_v1_5.new(pkey).sign(h)
result = base64.b64encode(signature).decode()
Here I am getting a string as result. But on the server side my signature is not matching.
Is there anything I am going wrong with ?? Can anyone help me on this ?
I came back to this question recently and noticed it was never resolved. I don't know what was going wrong with the OPs setup but the following code worked for me.
First, the python code that generates the signature of "Hello world":
from Cryptodome.Signature import PKCS1_v1_5
from Cryptodome.Hash import SHA256
from Cryptodome.PublicKey import RSA
import base64
def sign(message: str, private_key_str: str) -> str:
priv_key = RSA.importKey(private_key_str)
h = SHA256.new(message.encode('utf-8'))
signature = PKCS1_v1_5.new(priv_key).sign(h)
result = base64.b64encode(signature).decode()
return result
And now the Java code that verifies it:
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
...
...
public static boolean verify(String message, String b64Sig, byte[] pubkey_spki) throws GeneralSecurityException {
var pubKey = (PublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pubkey_spki));
var verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(pubKey);
verifier.update(message.getBytes(StandardCharsets.UTF_8));
return verifier.verify(Base64.getDecoder().decode(b64Sig));
}
Perhaps the trickiest part of this is specifying the correct padding scheme in each language/library. These signatures use the scheme identified as RSASSA-PKCS1-v1_5 in the PKCS#1 RFC 8017. On the python side this is accomplished by providing the SHA256 hash object to the PKCS1_v1_5 signature object. In Java it is perhaps a little more straightforward in that you ask for Signature object that implements the RSA algorithm with SHA256 as the hash function, but still have to know that this is RSASSA-PKCS1-v1_5 and not some other possibility in RFC 8017.
I think if one is not already something of an expert then understanding that these magic choices in python and Java produce compatible code is going to be difficult.

Problem publishing JSON output to PubSub. A 'u' is being added to every field

I have a script that pulls from the city if Chicago and grabs a json file and then published to Pub Sub. Once the data gets into pub sub I have a dataflow template that pulls the data into Google Big Query. The final data move to BQ is failing and when I print the output in the script. I am getting a u' in front of all the fields which I believe is messing up the field match. Has anyone else had this issue and know what is wrong with my code and how to possibly remove the 'u'. I have tried multiple fix but none of them have worked. A sample out put is listed below:
('_last_updt', '2010-07-21 14:50:53.0'), ('_length', '0.69'), ('_lif_lat', '41.985032613'),
My code is listed below:
from __future__ import unicode_literals
from sodapy import Socrata
import json
from io import StringIO
from google.oauth2 import service_account
from oauth2client.client import GoogleCredentials
from google.cloud import pubsub_v1
import time
import datetime
import urllib
import urllib.request
import argparse
import base64
credentials = GoogleCredentials.get_application_default()
# change project to your Project ID
project="xxxx"
# change topic to your PubSub topic name
topic="xxxx"
res = urllib.request.urlopen('https://data.cityofchicago.org/resource/8v9j-bter.json')
res_body = res.read()
traffic=json.loads(res_body)
publisher = pubsub_v1.PublisherClient()
topicName = 'projects/' + project + '/topics/' + topic
publisher = pubsub_v1.PublisherClient()
topic_path = publisher.topic_path(project,topic)
for key in traffic:
publisher.publish(topicName,str.encode(str(key)))
print(key.items())
You are describing a Python construction: Unicode strings are shown with a u' prefix.
See:
What's the u prefix in a Python string?
For example, building an array with a "normal" string and an unicode one:
>>> [u'a', 'a']
[u'a', 'a']
Don't worry too much about it, they are identical strings:
>>> u'a' == 'a'
True
Now when you say "I am getting a u' in front of all the fields which I believe is messing up the field match." Where do you see this? Is this part of the Python code, or do you see these u' show up on the BigQuery web UI too?
Looking at the code you posted, is seems to be forcing all strings to be Unicode with from __future__ import unicode_literals:
>>> "a"
'a'
>>> from __future__ import unicode_literals
>>> "a"
u'a'
https://python-future.org/unicode_literals.html

urllib.quote_plus doesn't encode plus

Here's what I'm doing:
from urllib import quote_plus
email = quote_plus('name+other#gmail.com')
but
print email
> name+other%40gmail.com
so if I put it in a URL the + becomes a space when I pull it out. But I want it to stay a plus. What am I doing wrong?
Try to define safe parameter explicitly, like in the code below:
from urllib import quote_plus
email = quote_plus('name+other#gmail.com', safe='/')
print email
If that works the reason I can assume is that the source code of the urllib.quote_plus has been modified somehow...

RSA encryption in Python vs Ruby

I am trying to encrypt a small string using Python and Ruby. I've written code in both these languages that should do exactly the same thing:
In Python:
from Crypto.PublicKey import RSA
from Crypto.Util import asn1
from Crypto import Random
import sys, time, signal, socket, requests, re, base64
pubkey = "9B596422997705A8805F25232C252B72C6B68752446A30BF9117783FE094F8559CA4A7AA5DBECAEC163596E96CD9577BDF232EF2F45DC474458BDA8EC272311924B8A176896E690135323D16800CFB9661352737FEDA9FB8DD44B6025EA8037CBA136DAE2DC0061B2C66A6F564E2C9E9579DAFD9BFF09ACF3B6E39BF363370F4A8AD1F88E3AE9A7F2C1B1C75AC00EAE308F57EC9FBDA244FC8B0D1234677A6BEE228FEE00BF653E8E010D0E59A30D0A1194298E052399A62E6FBD490CF03E16A1166F901E996D53DE776169B4EE8705E1512CCB69F8086C66213667A070A65DA28AF18FC8FC01D37158706A0B952D0963A9A4E4A6451758710C9ADD1245AB057389535AB0FA1D363A29ED8AE797D1EE958352E55D4AD4565C826E9EF12FA53AE443418FD704091039E190690FD55BF32E7E8C7D7668B8F0550C5E650C7D021F63A5055B7C1AEE6A669079494C4B964C6EA7D131FA1662CF5F5C83721D6F218038262E9DDFE236015EE331A8556D934F405B4203359EE055EA42BE831614919539A183C1C6AD8002E7E58E0C2BCA8462ADBF3916C62857F8099E57C45D85042E99A56630DF545D10DD338410D294E968A5640F11C7485651B246C5E7CA028A5368A0A74E040B08DF84C8676E568FC12266D54BA716672B05E0AA4EE40C64B358567C18791FD29ABA19EACA4142E2856C6E1988E2028703B3E283FA12C8E492FDB"
foobar = "foobar"
pubkey_int = long(pubkey,16)
pub_exp = 65537L
pubkey_obj = RSA.construct((pubkey_int, pub_exp))
encypted_data = pubkey_obj.encrypt(foobar, pub_exp)
encypted_data_b64 = base64.b64encode(encypted_data[0])
print encypted_data_b64
In Ruby:
require 'openssl'
require 'base64'
pubkey = "9B596422997705A8805F25232C252B72C6B68752446A30BF9117783FE094F8559CA4A7AA5DBECAEC163596E96CD9577BDF232EF2F45DC474458BDA8EC272311924B8A176896E690135323D16800CFB9661352737FEDA9FB8DD44B6025EA8037CBA136DAE2DC0061B2C66A6F564E2C9E9579DAFD9BFF09ACF3B6E39BF363370F4A8AD1F88E3AE9A7F2C1B1C75AC00EAE308F57EC9FBDA244FC8B0D1234677A6BEE228FEE00BF653E8E010D0E59A30D0A1194298E052399A62E6FBD490CF03E16A1166F901E996D53DE776169B4EE8705E1512CCB69F8086C66213667A070A65DA28AF18FC8FC01D37158706A0B952D0963A9A4E4A6451758710C9ADD1245AB057389535AB0FA1D363A29ED8AE797D1EE958352E55D4AD4565C826E9EF12FA53AE443418FD704091039E190690FD55BF32E7E8C7D7668B8F0550C5E650C7D021F63A5055B7C1AEE6A669079494C4B964C6EA7D131FA1662CF5F5C83721D6F218038262E9DDFE236015EE331A8556D934F405B4203359EE055EA42BE831614919539A183C1C6AD8002E7E58E0C2BCA8462ADBF3916C62857F8099E57C45D85042E99A56630DF545D10DD338410D294E968A5640F11C7485651B246C5E7CA028A5368A0A74E040B08DF84C8676E568FC12266D54BA716672B05E0AA4EE40C64B358567C18791FD29ABA19EACA4142E2856C6E1988E2028703B3E283FA12C8E492FDB"
foobar = "foobar"
asn1_sequence = OpenSSL::ASN1::Sequence.new(
[
OpenSSL::ASN1::Integer.new("0x#{pubkey}".to_i(16)),
OpenSSL::ASN1::Integer.new("0x10001".to_i(16))
]
)
public_key = OpenSSL::PKey::RSA.new(asn1_sequence)
data = Base64.encode64(public_key.public_encrypt(foobar))
puts data
Both these scripts are trying to encrypt the string foobar using the same public key. I expected both of them to output the same results each time, however this is not the case. Furthermore, every time the Ruby Script is executed, it outputs a different result.
Can someone help me identify the difference between these two scripts that is responsible for this behavior?
I am able to solve this issue by reading the documentation for Class _RSAobj (https://www.dlitz.net/software/pycrypto/api/current/Crypto.PublicKey.RSA._RSAobj-class.html#encrypt)
Attention: this function performs the plain, primitive RSA encryption
(textbook). In real applications, you always need to use proper
cryptographic padding, and you should not directly encrypt data with
this method. Failure to do so may lead to security vulnerabilities. It
is recommended to use modules Crypto.Cipher.PKCS1_OAEP or
Crypto.Cipher.PKCS1_v1_5 instead.
Looks like cryptographic padding is not used by default in the RSA module for Python, hence the difference.
Modified Python Script:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import sys, time, signal, socket, requests, re, base64
pubkey = "9B596422997705A8805F25232C252B72C6B68752446A30BF9117783FE094F8559CA4A7AA5DBECAEC163596E96CD9577BDF232EF2F45DC474458BDA8EC272311924B8A176896E690135323D16800CFB9661352737FEDA9FB8DD44B6025EA8037CBA136DAE2DC0061B2C66A6F564E2C9E9579DAFD9BFF09ACF3B6E39BF363370F4A8AD1F88E3AE9A7F2C1B1C75AC00EAE308F57EC9FBDA244FC8B0D1234677A6BEE228FEE00BF653E8E010D0E59A30D0A1194298E052399A62E6FBD490CF03E16A1166F901E996D53DE776169B4EE8705E1512CCB69F8086C66213667A070A65DA28AF18FC8FC01D37158706A0B952D0963A9A4E4A6451758710C9ADD1245AB057389535AB0FA1D363A29ED8AE797D1EE958352E55D4AD4565C826E9EF12FA53AE443418FD704091039E190690FD55BF32E7E8C7D7668B8F0550C5E650C7D021F63A5055B7C1AEE6A669079494C4B964C6EA7D131FA1662CF5F5C83721D6F218038262E9DDFE236015EE331A8556D934F405B4203359EE055EA42BE831614919539A183C1C6AD8002E7E58E0C2BCA8462ADBF3916C62857F8099E57C45D85042E99A56630DF545D10DD338410D294E968A5640F11C7485651B246C5E7CA028A5368A0A74E040B08DF84C8676E568FC12266D54BA716672B05E0AA4EE40C64B358567C18791FD29ABA19EACA4142E2856C6E1988E2028703B3E283FA12C8E492FDB"
foobar = "foobar"
pubkey_int = long(pubkey,16)
pub_exp = 65537L
pubkey_obj = RSA.construct((pubkey_int, pub_exp))
cipher = PKCS1_v1_5.new(pubkey_obj)
encypted_data = cipher.encrypt(foobar)
encypted_data_b64 = base64.b64encode(encypted_data)
print encypted_data_b64

Categories