RSA generate private key from data with python - python

I have a cipher message in base64 and a pubkey.pem with the public key information. So because the key is small(576) I have recovered all the needed information to reconstruct the private key : p,q and d.
Now I want to decipher the message but I don't know how to do it. Indeed if I want to use the decrypt function I need an priv_key object but I don't know how to generate it from (n,e,d)
from Crypto.PublicKey import RSA
from base64 import b64decode
#message I want to decipher
msg="e8oQDihsmkvjT3sZe+EE8lwNvBEsFegYF6+OOFOiR6gMtMZxxba/bIgLUD8pV3yEf0gOOfHuB5bC3vQmo7bE4PcIKfpFGZBA"
pub_key64 = 'MGQwDQYJKoZIhvcNAQEBBQADUwAwUAJJAMLLsk/b+SO2Emjj8Ro4lt5FdLO6WHMMvWUpOIZOIiPu63BKF8/QjRa0aJGmFHR1mTnG5Jqv5/JZVUjHTB1/uNJM0VyyO0zQowIDAQAB'
pub_keyDER = b64decode(pub_key64)
pub_key_obj = RSA.importKey(pub_keyDER) #my weak public key
... # how to generate priv_key_obj ???
dsmg=priv_key_obj.decrypt(msg)

You can construct a private from components in the following way (documentation):
from Crypto.PublicKey import RSA
# assume d was correctly calculated
n = 1234....L
e = 65537L
d = 43434...L
private_key = RSA.construct((n, e, d))
dsmg = private_key.decrypt(msg)

Related

How to add a custom RSA key pair to a .pem file

I created a custom RSA key pair just for test purposes in python. I want to add the private key and public key to a .pem file but I didnt find anything in my research. All i found is people generating a RSA key pair from a library.
I have the e, d and n variables for the public key[e, n] and private key[d, n].
Most major crypto libraries support this, e.g. PyCryptodome (via construct() and exportKey()) or Cryptography (as described in the Numbers and Key Serialization sections), e.g.
PyCryptodome:
from Crypto.PublicKey import RSA
n = int("b83b...529b", 16);
d = int("4eea...a721", 16);
e = int("010001", 16);
privateKey = RSA.construct((n, e, d))
privateKeyPem = privateKey.exportKey(pkcs=8) # export in PKCS#8 format
publicKey = RSA.construct((n, e))
publicKeyPem = publicKey.exportKey() # export in X.509/SPKI format
print(privateKeyPem.decode('utf8'))
print(publicKeyPem.decode('utf8'))
or Cryptography:
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
n = int("b83b...529b", 16);
d = int("4eea...a721", 16);
e = int("010001", 16);
(q, p) = rsa.rsa_recover_prime_factors(n, e, d)
dmq1 = rsa.rsa_crt_dmq1(d, q)
dmp1 = rsa.rsa_crt_dmp1(d, p)
iqmp = rsa.rsa_crt_iqmp(p, q)
publicNumbers = rsa.RSAPublicNumbers(e, n)
privateNumbers = rsa.RSAPrivateNumbers(p, q, d, dmp1, dmq1, iqmp, publicNumbers)
privateKey = privateNumbers.private_key();
publicKey = publicNumbers.public_key();
privateKeyPem = privateKey.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
publicKeyPem = publicKey.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
print(privateKeyPem.decode('utf8'))
print(publicKeyPem.decode('utf8'))
Note that the raw key is symmetric in p and q, so swapping p and q changes the PEM or DER encoded key, but not the raw key (n, e, d).

Migrate RSA decryption from PyCrypto to PyCryptodome

Using the PyCrypto library, the following code prints 127:
from Crypto.PublicKey import RSA
import base64
# Private key in tuple form (obscured for privacy)
key = [1, 1, 1]
bk = "zJuG60z9Iv..." # (obscured for privacy)
privatekey = RSA.construct(key)
result = privatekey.decrypt(base64.b64decode(bk))
print(len(result))
To the best of my knowledge, this would be the equivalent using PyCryptodome. However, the resulting value only has a length of 16, indicating a possible decryption error.
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
# Private key in tuple form (obscured for privacy)
key = [1, 1, 1]
bk = "zJuG60z9Iv..." # (obscured for privacy)
privatekey = RSA.construct(key)
cipher = PKCS1_v1_5.new(privatekey)
result = cipher.decrypt(base64.b64decode(bk), None)
print(len(result))
I believe this is because my ciphertext uses textbook unpadded RSA. Does anyone know how I can decrypt this value with PyCryptodome or another maintained library?
PyCryptodome doesn't provide a built-in method to decrypt textbook RSA, but can be decrypted using modular exponentiation from the standard library.
from Crypto.PublicKey import RSA
import base64
# Private key in tuple form (obscured for privacy)
key = [1, 1, 1]
bk = "zJuG60z9Iv..." # (obscured for privacy)
privatekey = RSA.construct(key)
ciphertext = base64.b64decode(bk)
ct_int = int.from_bytes(ciphertext, 'big')
pt_int = pow(ct_int, privatekey.d, privatekey.n)
plaintext = pt_int.to_bytes(privatekey.size_in_bytes(), 'big').lstrip(b'\x00')
print(len(plaintext))

Python AES.MODE_CTR does not decrypt as expected

I am trying to rewrite a node.js decoding function in python
this is the function I am trying to rewrite
module.exports.decrypt = function (data, key, iv, hmacKey) {
iv = iv.slice(0, 16)
var decipherer = crypto.createDecipheriv('aes-128-ctr', key, iv)
var hmac
if (hmacKey) {
hmac = crypto.createHmac('sha1', hmacKey).update(data).digest()
}
return {
data: decipherer.update(data),
hmac: hmac
}
}
the key parameter is generated by crypto.pbkdf2Sync function of node's standard library.
What I implemented in python is
from Crypto.Cipher import AES
from Crypto.Util import Counter
def decrypt(data, key, iv, hmac=None):
iv = iv[:16]
ctr = Counter.new(128)
cipher = AES.new(key, mode=AES.MODE_CTR, IV=iv, counter=ctr)
return cipher.decrypt(data)
I provided the python decrypt function the same same data that the js function receives.
since the data and key, iv params that the js function expects are binary buffers, I copied them to the python code as hex strings and then used binascii.unhexlify in the python code before passing them to the ecrypt python function.
so the arguments that I am providing to both functions are (hex)
data 972acf88c5d7
key 129b6e542600889a75ec7659d9dc23df
iv 31323331323331323331323331323331323331323331313233313233313233313233
The python function returns gibberish.
can anyone help?
thanks!

Why Python and Node.js's HMAC result is different in this code?

Recently, I have a task to make HMAC to communicate API server.
I got a sample code of node.js version which makes HMAC of message. Using concept and sample, I've got to make a python code which is equivalent with node.js version but result is different, but I have no idea why.
Please review both code and help finding the difference.
Python 3.0
import hmac
import string
import hashlib
import base64
secret = 'PYPd1Hv4J6'
message = '1515928475.417'
key = base64.b64encode(secret.encode('utf-8'))
hmac_result = hmac.new(key, message.encode('utf-8'), hashlib.sha512)
print(base64.b64encode(hmac_result.digest()))
Result (Python 3.6)
b'7ohDRJGMGYjfHojnrvNpM3YM9jb+GLJjbQvblzrE17h2yoKfIRGEBSjfOqQFO4iKD7owk+gSciFxFkNB+yPP4g=='
Node.JS
var crypto = require('crypto');
var secret = 'PYPd1Hv4J6';
var message = '1515928475.417'
var key = Buffer(secret, 'base64');
var hmac = crypto.createHmac('sha512', key);
var hmac_result = hmac.update(message).digest('base64');
console.log(hmac_result)
Result (Node.JS 6.11)
m6Z/FxI492VXKDc16tO5XDNvty0Tmv0b1uksSbiwh87+4rmg43hEXM0WmWzkTP3aXB1s5rhm05Hu3g70GTrdEQ==
Your input keys are different, so the outputs will be different.
Node:
var secret = 'PYPd1Hv4J6';
var message = '1515928475.417'
var key = Buffer(secret, 'base64'); // buffer of bytes from the base64-encoded string 'PYPd1Hv4J6'
// <Buffer 3d 83 dd d4 7b f8 27>
Python:
secret = 'PYPd1Hv4J6'
message = '1515928475.417'
key = base64.b64encode(secret.encode('utf-8')) # did you mean b64decode here?
I was able to get them to match by stripping out the base64ing of everything:
Python:
import hmac
import string
import hashlib
import base64
secret = 'PYPd1Hv4J6'
message = '1515928475.417'
key = secret.encode('utf-8')
hmac_result = hmac.new(key, message.encode('utf-8'), hashlib.sha512)
print(base64.b64encode(hmac_result.digest()))
Output:
b'jezLNuBz37FoACm4LdLSqOQ5C93cuGID9a8MQmOZntXklDV3SvWdNfqndzK0a54awKeHY+behFiv4FYyILRoGQ=='
Javascript:
var crypto = require('crypto');
var secret = 'PYPd1Hv4J6';
var message = '1515928475.417'
var hmac = crypto.createHmac('sha512', secret);
var hmac_result = hmac.update(message).digest('base64');
console.log(hmac_result)
Output:
jezLNuBz37FoACm4LdLSqOQ5C93cuGID9a8MQmOZntXklDV3SvWdNfqndzK0a54awKeHY+behFiv4FYyILRoGQ==
Equivalent/Expected python code's is below.
import hmac
import string
import hashlib
import base64
secret = 'PYPd1Hv4J6=='
message = '1515928475.417'
key = base64.b64decode (secret.encode('utf-8'))
hmac_result = hmac.new(key, message.encode('utf-8'), hashlib.sha512)
print(base64.b64encode(hmac_result.digest()))
Padding '=' to targeted and decoding part was important.
Thank you.

PyCrypto: Attribute Error: 'NoneType' object has no attribute 'oid' while using PKCS1_v1_5

SHA = hashlib.sha1()
Eh = SHA.update(chunk)
HRSA.signSHA(Eh,RSAprivatekey)
RSAprivatekey is read in HRSA module and passed as argument to this function:
RSAprivatekey = RSA.importKey(infile.read())
infile points to the 'privatekey.txt' which contained only the RSAprivatekey.
HRSA is a module I've created which basically does this:
def signSHA(hash, key):
signer = PKCS1_v1_5.new(key)
D = signer.sign(hash)
return D
I'm being shown the following error:
File "D:\Study\Sem V\Hybrid Encryption\Phase 2\HRSA.py", line 57, in signSHA
D = signer.sign(hash)
File "C:\Python33\lib\site-packages\Crypto\Signature\PKCS1_v1_5.py", line 110, in sign
em = EMSA_PKCS1_V1_5_ENCODE(mhash, k)
File "C:\Python33\lib\site-packages\Crypto\Signature\PKCS1_v1_5.py", line 211, in EMSA_PKCS1_V1_5_ENCODE
digestAlgo = DerSequence([hash.oid, DerNull().encode()])
AttributeError: 'NoneType' object has no attribute 'oid'
How could I fix this since it's a bug with the PyCrypto code?
hashfunc.update(arg) doesn't return anything. It's there to update the internal state of the hashing function with new input data. If you want to convert the internal state into a hash, then you need to call either hashfunc.digest() or hashfunc.hexdigest().
It would look like this:
Eh = hashlib.sha1(chunk).digest()
HRSA.signSHA(Eh, RSAprivatekey)
You must use the PyCrypto module for SHA1, so:
from Crypto.Hash import SHA1
sha_obj = SHA1.new()
sha_obj.update(chunk)
HRSA.signSHA(sha_obj,RSAprivatekey)
The reason is that the PKCS#1v1.5 signature embeds the ASN.1 Object ID of the hash, but the SHA-1 object obtained from the standard library does not include/know it.
As mentioned, hashlib does not work well with PyCryptodome.
To provide a little more detailed example:
from Crypto.Hash import SHA256
from Crypto.Signature import pkcs1_15
from Crypto.PublicKey import RSA
# Generate a new RSA key pair with the specified key length
key_length = 1024
key = RSA.generate(key_length)
# Get the RSA keys
private_key = key.export_key()
public_key = key.publickey().export_key()
msg = b"The aliens are coming!"
hash = SHA256.new(msg)
# Generate the signature
signer = pkcs1_15.new(RSA.import_key(private_key))
signature = signer.sign(hash)
verifier = pkcs1_15.new(RSA.import_key(public_key))
#Exception will be thrown if verification fails
verifier.verify(hash, signature)

Categories