python gnupg not encrypting file - python

I am trying to encrypt a file with a GPG key but the output is keeps being empty:
>>> import gnupg
>>> home_dir = '~/.gnupg'
>>> pgp = gnupg.GPG(gnupghome=home_dir)
>>> key = open('ff.asc', 'rb')
>>> fp = open('test.txt', 'rb')
>>> res = pgp.import_keys(key.read())
>>> res.results
[{'fingerprint': 'C3...', 'text': 'Not actually changed\n', 'ok': '0'}]
>>> enc = pgp.encrypt_file(fp, 'C3...')
>>> enc.data
b''
What am I missing here?
Also, is it possible to pass the public GPG key directly to the encryption function from a string without having to import it?

The problem may be that the imported key is not trusted. From the documentation of gnupg:
Note:
Any public key provided for encryption should be trusted, otherwise
encryption fails but without any warning. This is because gpg just
prints a message to the console, but does not provide a specific error
indication that the Python wrapper can use.
The simplest solution is to use the always_trust keyword argument of encryption functions:
always_trust (defaults to False) - Skip key validation and
assume that used keys are always fully trusted.
Thus your encryption statement should read
enc = pgp.encrypt_file(fp, 'C3...', always_trust=True)

Related

Decrypting and encrypting java JWEObject with algorithm RSA-OAEP-256 on python

I have a kafka message that was encrypted on java with the following code:
private String decryptedMessage(String key, String encryptedMessage) throws NoSuchAlgorithmException, InvalidKeySpecException, ParseException, JOSEException {
PrivateKey privateKey = <some way to generate a private key from key>;
JWEDecrypter decrypter = new RSADecrypter(privateKey);
JWEObject decryptedJweObj = JWEObject.parse(encryptedMessage);
decryptedJweObj.decrypt(decrypter);
return decryptedJweObj.getPayload().toJSONObject().toJSONString();
}
Now I'm trying to decode it using python on a decoded message where I already know the private key.
I tried using jwcrypto (since I'm using python3 and jeso is only for 2.x) using this code like in their documents, but it didn't work:
enc = '<encrypted message>'
private = '<private key>'
jwetoken = jwe.JWE()
jwetoken.deserialize(enc, key=private_key)
payload = jwetoken.payload
And I get this error code: jwcrypto.jwe.InvalidJWEData: No recipient matched the provided key["Failed: [ValueError('key is not a JWK object',)]"] I tried looking for a way to make the private key a JWK object but couldn't find one.
I know my message is JWE since it's split by 4 dots and when I base64 decode the first part I get this json: b'{"alg":"RSA-OAEP-256","enc":"A256GCM","kid":"<some key id>"}'
So I'm kind of stuck on how to decode my message.
Decrypted string: {"value":"Object Encryption"}
Encrypted string:
eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIiwia2lkIjoiYjFhOWVmNzAtYjQ4Yy00YzdiLWI0ZTQtODU2YzQyNGIyYzZlIn0.XzLgQTzESD7mg-DtiwFaOQQIfJjQOox5Efbq3Cn8n4H0OZUNvNFWuLr2gPH4WqhWZFYvYh6Mx3--bKiYA_kGplPaJUdPfuYx3OgOug9fuYMrZesE-9stJFd4TnQOJcrTfehJkI_QKPqfWgbEgh1Zn8r7DuIBbABmNK4OHa0edwUA0Lu4mUxzRW6UPaNdWtfEGL9ZVR4lzUx6QX6nweKdbi8tkDnQrSNcQ4eZKIn8mVl5rL3s-qa2VC1Zvo4R-eA4jTKs6WQrkPChJkfoECcYcLx7SIHdxP6VB9DAhW-TwRizr5OZUVLLLH3UEOF77Rtc6MLL4Al5mo29sE-E1faywQ.R1QE-zY29Ed7yfqX.-soXsfltkJL0AXk_q5tPn9hagCBG_1c03VKdh2A.-oteTYv0SHzE4yBmZlterg
Decryption key (need to decode with base64):
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQChyho54VxOGYDxrN2pjM8/pA94kcqlMNZ0NSIoSHhasAm72X66XN9GI2IapQETy7+gNBKBWszWn4JsNuAbLLNp5zeTlmzHp09ee4L+g8s/NIKMwA5Mgx9wGu2Hi0foh0pErAMKQV6CLBJUfB5JUu9PX2MED7Z2XGG0RYClSMEO8L7iHXm1ooCr83rU/U5xXwpuTrp4L9nYD9eB6EptCgOWEi98lq5oeQXNyWfti3/gckathUi8WINlI+5/fPv7ZWd9Z60VXAVfb5u861/erIhEIJRkqbDXc/ULAQsAeEKVYzHpStM9In30mQdp6EdY48imZiHj1GNgPvY+MD3wPmdTAgMBAAECggEAE3IcJtrMYmK0WdfiKI/RFSAd7+ruBV7SV9NPELJtLNE9ykNA9RtWhrKYBwXQFFYH6TR5CO0l86HmZiVOWFXOFquAxY9t8a1NX9jOjNLAag9gpZQr48xayfmilQkLkoo4Rfq6vs/OkSzE4zyr0zpRoyOe3g0ZbC58W9OCu9r7wVTDV+KKE8ChU39Ae8HLfMEQXWSIUqxbrpw+mLeFX1qh5ILNBDA9M6vD+JuoiuIZltW4djnlU4hxYPVwTyuPBCQ3AwJsRGcddfxWTI+kIm2/6k8HzhdpB1ajBrZX/XVeXAp7VlvyHzBZ5ri1NDpr/Cyh6o2ysdB8qGCnlDcsNHLl+QKBgQDTORonO1FrIAo2VnsQS0Lq6EdxRzzP9q9mHttJNJK5eEXP7sNSdTDrudk4tpr3zvXtK4b+4SiCDriA5VTJHhdGF3wwqhR76XT3gLoXZLGYlx+4RvMbuIFDGkUee+39T2//MztEZgt3TM3LcBFEjTRV8gzpFJsj8wea3E4B8lOEZQKBgQDEFkfdgIBNu/3wH+z2uq40kYlkMRb4wQq8CjmwXYxGu1WR3SYn2zNQTsZR6BtiHFzx/37W279dO87u9rAbNuY5V9VYQKjxZD2lidYQ/0w07kO1PhNuISLpqn2AbiLczlLluX8dHpLpb5UG+JWlqih5VBCDFktmVUlMVteHPa21VwKBgCkpEHqiqYwJk1PhaFvVfrXOC9X8PtJ7zNRGoQ7T6t+vm1MYwQE5iw30imrt0qcFspDEEatrbvxhJ/0eM3Z5oalr/CxziEhZRwzQDfNvENieYnUDhm5Zdv7/iIaXOdpJ95YwgpUimYtm8Rd6wDKunYs9/twQwuavfkTkN2NTuIitAoGBAJu0NYylpTwUsyghscCZrAsCJd7xPBR69VMrq3NoVSM1TlVtDgdIAA8c/k27yUK20vc2sjladTJLc549NMnnZhjSrg5OCdjkiC8SrHECyDifmhQpHrSsi1SQlOeOjRBYpWrVSSKOTIogmG3YprvNyiXNou70nRq9Tl7X9nzldTIxAoGBAJ3qo/epO7xAs6Vhp+8na0Tv93Ji2kCvA14iOE+P08saldspB4NEVitGahuvrTx8CKDyL1PDH5X1MTabvI/LYw6k/gnzOhSX3MTP3qMepNEq1A5chvMJHhMS72/tAPKIXux+AgDkSvq8+G02DFWDpF9bcBoINL/89wOUcEfOQty0
The posted encrypted token can be decrypted with the posted RSA key and the Python library JWCrypto. Maybe it doesn't work for you because of a key import bug.
The posted RSA key is a DER encoded PKCS#8 key (Base64 encoded). JWCrypto does not support this encoding directly, but only the PEM encoding, which is not too bad, because the conversion from DER to PEM is trivial: The Base64 string must be formatted (line break after every 64 characters) and the header (-----BEGIN PRIVATE KEY-----) and footer (-----END PRIVATE KEY-----) must be added each in a separate line.
Alternatively, the key can be converted to a JWK and imported in this format.
The following Python code shows these two variants based on the posted data. For this the JWK was derived with online tools from the posted PKCS#8 key:
pkcs8pem = b'''-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQChyho54VxOGYDx
rN2pjM8/pA94kcqlMNZ0NSIoSHhasAm72X66XN9GI2IapQETy7+gNBKBWszWn4Js
NuAbLLNp5zeTlmzHp09ee4L+g8s/NIKMwA5Mgx9wGu2Hi0foh0pErAMKQV6CLBJU
fB5JUu9PX2MED7Z2XGG0RYClSMEO8L7iHXm1ooCr83rU/U5xXwpuTrp4L9nYD9eB
6EptCgOWEi98lq5oeQXNyWfti3/gckathUi8WINlI+5/fPv7ZWd9Z60VXAVfb5u8
61/erIhEIJRkqbDXc/ULAQsAeEKVYzHpStM9In30mQdp6EdY48imZiHj1GNgPvY+
MD3wPmdTAgMBAAECggEAE3IcJtrMYmK0WdfiKI/RFSAd7+ruBV7SV9NPELJtLNE9
ykNA9RtWhrKYBwXQFFYH6TR5CO0l86HmZiVOWFXOFquAxY9t8a1NX9jOjNLAag9g
pZQr48xayfmilQkLkoo4Rfq6vs/OkSzE4zyr0zpRoyOe3g0ZbC58W9OCu9r7wVTD
V+KKE8ChU39Ae8HLfMEQXWSIUqxbrpw+mLeFX1qh5ILNBDA9M6vD+JuoiuIZltW4
djnlU4hxYPVwTyuPBCQ3AwJsRGcddfxWTI+kIm2/6k8HzhdpB1ajBrZX/XVeXAp7
VlvyHzBZ5ri1NDpr/Cyh6o2ysdB8qGCnlDcsNHLl+QKBgQDTORonO1FrIAo2VnsQ
S0Lq6EdxRzzP9q9mHttJNJK5eEXP7sNSdTDrudk4tpr3zvXtK4b+4SiCDriA5VTJ
HhdGF3wwqhR76XT3gLoXZLGYlx+4RvMbuIFDGkUee+39T2//MztEZgt3TM3LcBFE
jTRV8gzpFJsj8wea3E4B8lOEZQKBgQDEFkfdgIBNu/3wH+z2uq40kYlkMRb4wQq8
CjmwXYxGu1WR3SYn2zNQTsZR6BtiHFzx/37W279dO87u9rAbNuY5V9VYQKjxZD2l
idYQ/0w07kO1PhNuISLpqn2AbiLczlLluX8dHpLpb5UG+JWlqih5VBCDFktmVUlM
VteHPa21VwKBgCkpEHqiqYwJk1PhaFvVfrXOC9X8PtJ7zNRGoQ7T6t+vm1MYwQE5
iw30imrt0qcFspDEEatrbvxhJ/0eM3Z5oalr/CxziEhZRwzQDfNvENieYnUDhm5Z
dv7/iIaXOdpJ95YwgpUimYtm8Rd6wDKunYs9/twQwuavfkTkN2NTuIitAoGBAJu0
NYylpTwUsyghscCZrAsCJd7xPBR69VMrq3NoVSM1TlVtDgdIAA8c/k27yUK20vc2
sjladTJLc549NMnnZhjSrg5OCdjkiC8SrHECyDifmhQpHrSsi1SQlOeOjRBYpWrV
SSKOTIogmG3YprvNyiXNou70nRq9Tl7X9nzldTIxAoGBAJ3qo/epO7xAs6Vhp+8n
a0Tv93Ji2kCvA14iOE+P08saldspB4NEVitGahuvrTx8CKDyL1PDH5X1MTabvI/L
Yw6k/gnzOhSX3MTP3qMepNEq1A5chvMJHhMS72/tAPKIXux+AgDkSvq8+G02DFWD
pF9bcBoINL/89wOUcEfOQty0
-----END PRIVATE KEY-----'''
jwkey = {"p":"0zkaJztRayAKNlZ7EEtC6uhHcUc8z_avZh7bSTSSuXhFz-7DUnUw67nZOLaa98717SuG_uEogg64gOVUyR4XRhd8MKoUe-l094C6F2SxmJcfuEbzG7iBQxpFHnvt_U9v_zM7RGYLd0zNy3ARRI00VfIM6RSbI_MHmtxOAfJThGU","kty":"RSA","q":"xBZH3YCATbv98B_s9rquNJGJZDEW-MEKvAo5sF2MRrtVkd0mJ9szUE7GUegbYhxc8f9-1tu_XTvO7vawGzbmOVfVWECo8WQ9pYnWEP9MNO5DtT4TbiEi6ap9gG4i3M5S5bl_HR6S6W-VBviVpaooeVQQgxZLZlVJTFbXhz2ttVc","d":"E3IcJtrMYmK0WdfiKI_RFSAd7-ruBV7SV9NPELJtLNE9ykNA9RtWhrKYBwXQFFYH6TR5CO0l86HmZiVOWFXOFquAxY9t8a1NX9jOjNLAag9gpZQr48xayfmilQkLkoo4Rfq6vs_OkSzE4zyr0zpRoyOe3g0ZbC58W9OCu9r7wVTDV-KKE8ChU39Ae8HLfMEQXWSIUqxbrpw-mLeFX1qh5ILNBDA9M6vD-JuoiuIZltW4djnlU4hxYPVwTyuPBCQ3AwJsRGcddfxWTI-kIm2_6k8HzhdpB1ajBrZX_XVeXAp7VlvyHzBZ5ri1NDpr_Cyh6o2ysdB8qGCnlDcsNHLl-Q","e":"AQAB","kid":"79635991-092f-4576-a23a-4cbab618e8a8","qi":"neqj96k7vECzpWGn7ydrRO_3cmLaQK8DXiI4T4_TyxqV2ykHg0RWK0ZqG6-tPHwIoPIvU8MflfUxNpu8j8tjDqT-CfM6FJfcxM_eox6k0SrUDlyG8wkeExLvb-0A8ohe7H4CAORK-rz4bTYMVYOkX1twGgg0v_z3A5RwR85C3LQ","dp":"KSkQeqKpjAmTU-FoW9V-tc4L1fw-0nvM1EahDtPq36-bUxjBATmLDfSKau3SpwWykMQRq2tu_GEn_R4zdnmhqWv8LHOISFlHDNAN828Q2J5idQOGbll2_v-Ihpc52kn3ljCClSKZi2bxF3rAMq6diz3-3BDC5q9-ROQ3Y1O4iK0","dq":"m7Q1jKWlPBSzKCGxwJmsCwIl3vE8FHr1Uyurc2hVIzVOVW0OB0gADxz-TbvJQrbS9zayOVp1Mktznj00yedmGNKuDk4J2OSILxKscQLIOJ-aFCketKyLVJCU546NEFilatVJIo5MiiCYbdimu83KJc2i7vSdGr1OXtf2fOV1MjE","n":"ocoaOeFcThmA8azdqYzPP6QPeJHKpTDWdDUiKEh4WrAJu9l-ulzfRiNiGqUBE8u_oDQSgVrM1p-CbDbgGyyzaec3k5Zsx6dPXnuC_oPLPzSCjMAOTIMfcBrth4tH6IdKRKwDCkFegiwSVHweSVLvT19jBA-2dlxhtEWApUjBDvC-4h15taKAq_N61P1OcV8Kbk66eC_Z2A_XgehKbQoDlhIvfJauaHkFzcln7Yt_4HJGrYVIvFiDZSPuf3z7-2VnfWetFVwFX2-bvOtf3qyIRCCUZKmw13P1CwELAHhClWMx6UrTPSJ99JkHaehHWOPIpmYh49RjYD72PjA98D5nUw"}
enc = 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIiwia2lkIjoiYjFhOWVmNzAtYjQ4Yy00YzdiLWI0ZTQtODU2YzQyNGIyYzZlIn0.XzLgQTzESD7mg-DtiwFaOQQIfJjQOox5Efbq3Cn8n4H0OZUNvNFWuLr2gPH4WqhWZFYvYh6Mx3--bKiYA_kGplPaJUdPfuYx3OgOug9fuYMrZesE-9stJFd4TnQOJcrTfehJkI_QKPqfWgbEgh1Zn8r7DuIBbABmNK4OHa0edwUA0Lu4mUxzRW6UPaNdWtfEGL9ZVR4lzUx6QX6nweKdbi8tkDnQrSNcQ4eZKIn8mVl5rL3s-qa2VC1Zvo4R-eA4jTKs6WQrkPChJkfoECcYcLx7SIHdxP6VB9DAhW-TwRizr5OZUVLLLH3UEOF77Rtc6MLL4Al5mo29sE-E1faywQ.R1QE-zY29Ed7yfqX.-soXsfltkJL0AXk_q5tPn9hagCBG_1c03VKdh2A.-oteTYv0SHzE4yBmZlterg'
from jwcrypto import jwk, jwe
# Import of a PEM encoded PKCS#8 key
private_key = jwk.JWK.from_pem(pkcs8pem)
jwetoken = jwe.JWE()
jwetoken.deserialize(enc, key=private_key)
payload = jwetoken.payload
print(payload.decode('utf-8'))
# Import of a JWK
private_key = jwk.JWK(**jwkey)
jwetoken = jwe.JWE()
jwetoken.deserialize(enc, key=private_key)
payload = jwetoken.payload
print(payload.decode('utf-8'))
with the output:
{"value":"Object Encryption"}
{"value":"Object Encryption"}

Fernet encryption/decryption with python and kotlin

I have a project written in python. I use cryptography library to encrypt and decrypt data.
I do it how is shown in their tutorial.
Here is my python code:
import base64
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
password = b"my password"
salt = os.urandom(16)
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(password))
f = Fernet(key)
data = b"my data..."
token = f.encrypt(data)
Then for decryption I can just use:
f.decrypt(token)
Everything works perfectly in python but now I need to do the same thing in kotlin. I found out about fernet java-8 library but I don't know how to use it in the same way.
The problem is that I have two tools: one is written in python and another I want to write in kotlin. Both tools are meant to do the same thing - the python one is for desktop and the kotlin one is gonna be an android app. So it is really important for their encryption to be the same, so that files encrypted in python (desktop tool) can be decrypted in kotlin (android app) and vice versa.
But I don't know how to write analogous kotlin code.
You see there is a function (or class) called PBKDF2HMAC and there is also base64.urlsafe_b64encode and others. And I don't know what are analogous functions in kotlin or fernet java-8.
So how should I do it? Assuming that in kotlin I have to use password and salt I used in python.
Thanks!
In Java/Kotlin, using fernet-java8, the token generated with the Python code could be decrypted as follows:
import java.security.SecureRandom
import java.util.Base64
import javax.crypto.spec.PBEKeySpec
import javax.crypto.SecretKeyFactory
import com.macasaet.fernet.Key
import com.macasaet.fernet.Token
import com.macasaet.fernet.StringValidator
import com.macasaet.fernet.Validator
import java.time.Duration
import java.time.temporal.TemporalAmount
...
// Data from encryption
val salt = Base64.getUrlDecoder().decode("2Yb8EwpYkMlycHxoKcmHuA==")
val token = Token.fromString("gAAAAABfoAmp7C7IWVgA5urICEIspm_MPAGZ-SyGnPEVUBBNerWQ-K6mpSoYTwRkUt3FobyAFHbYfhNtiGMe_96yyLvUoeLIIg==");
// Derive Fernet key
val key = deriveKey("my password", salt)
val fernetKey = Key(key)
// Decrypt
val validator: Validator<String> = object : StringValidator {
override fun getTimeToLive(): TemporalAmount {
return Duration.ofHours(24)
}
}
val data = token.validateAndDecrypt(fernetKey, validator)
println(data) // my data...
with:
fun deriveKey(password: String, salt: ByteArray): String {
val iterations = 100000
val derivedKeyLength = 256
val spec = PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength)
val secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
val key = secretKeyFactory.generateSecret(spec).encoded
return Base64.getUrlEncoder().encodeToString(key)
}
Here the Fernet key is derived using the key derivation function PBKDF2. PBKDF2 expects various input parameters, such as a password, a digest, a salt, an iteration count and the desired key length. In the posted example the key is returned Base64url encoded.For decryption the same parameters must be used as for encryption. Since the salt is usually (as in the posted code) randomly generated during encryption, it must be passed to the decryption side along with the ciphertext (note: the salt is not a secret).
The validator sets the time-to-live (by default 60s) to 24h, see here for more details.
In the posted Python code the export of the salt has to be added, e.g. by Base64url encoding it analogous to key and token (and printing it for simplicity). In practice, salt and token could also be concatenated during encryption and separated during decryption.
Update:
The encryption part is analogous:
// Generate salt
val salt = generateSalt()
println(Base64.getUrlEncoder().encodeToString(salt))
// Derive Fernet key
val key = deriveKey("my password", salt)
val fernetKey = Key(key)
// Encrypt
val data = "my data..."
val token = Token.generate(fernetKey, data)
println(token.serialise()) // the Base64url encoded token
with
fun generateSalt(): ByteArray {
val random = SecureRandom()
val salt = ByteArray(16)
random.nextBytes(salt)
return salt
}

How to check if a key is already encrypted while using Fernet

I am trying to encrypt sensible values in my environment file using a python script. I am using Fernet. I want to encrypt only those values which are not already encrypted, making sure that there isn't any multi-level encryption.
How can I know that a value is already encrypted or decrypted in this case?
Simply attempt decryption with a TTL of None (the default). If it succeeds, then you don't need to do anything more. If it fails an InvalidToken exception will be raised which you can catch. Inside the except block you can then encrypt the file, as in the following example:
import base64
from pathlib import Path
from cryptography.fernet import Fernet, InvalidToken
key = Fernet.generate_key()
f = Fernet(key)
encrypted = f.encrypt(b'Hello world')
p1, p2 = Path('file1'), Path('file2')
p1.write_bytes(encrypted)
p2.write_bytes(base64.urlsafe_b64encode(b'\x80not encrypted'))
for example in (p1, p2):
try:
data = example.read_bytes()
f.decrypt(data, None)
except InvalidToken:
example.write_bytes(f.encrypt(data))

Python-GnuPG encryption returns blank(Key exist in home directory)

For sending secure mail i have using Python-GnuPG for encrypting the mail. So i started to follow the documentation and a tutorial on this link . I have created the key in home directory and started to testing for encrypting a string. While encrypting the string it returns blank and i have print the result of status of encrypted string it also returns blank. What will be the possible issue? Here's what i am tried already:
>>> import gnupg
>>> gpg = gnupg.GPG(gnupghome='/home/saravanan/.gnupg')
>>> unencrypted_string = 'Who are you? How did you get in my house?'
>>> encrypted_data = gpg.encrypt(unencrypted_string, 'test#mail.com')
>>> encrypted_string = str(encrypted_data)
>>> print encrypted_string
>>> print encrypted_data.status
From above both encrypted_string and encrypted_data.status returns blank.

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