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

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))

Related

ValueError("Expected: ASCII-armored PGP data") when using pgp_key.from_blob(key_string)

I am getting ValueError("Expected: ASCII-armored PGP data") when using pgp_key.from_blob(key_string) when trying to parse the key.
pgp_key = pgpy.PGPKey()
key = pgp_key.from_blob(key_string);
I tried using parse method as well but getting the same error.
I fixed this error by:
With your key as a file, run base64 /path/to/file_name new_encoded_file_name
Put your encoded key in your desired place (AWS Secrets Manager in my case)
Within your program, add the following line BEFORE getting your pgp key:
key_string = base64.decode(key_string)
Now key = pgp_key.from_blob(key_string) will no longer throw an error as the decoded string will be an ASCII-armored bytearray.

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
}

python gnupg not encrypting file

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)

Importing a RSA public key into python when in strong form

Essentially what I have here is a key from a ssh-rsa generator that was given to me in the form of a string as follows
AAAAB3NzaC1yc2EAAAADAQABAAABAQCsjE+uDO0v+il18nmkF0dJZaXOZVKfg7TG9l9Aod0rDiw2pNoQqCUHFGDE1HYXhK6NfVtCZdNDF+kF89EV9eygiN3RVPm5cwum45apT8N+mZsveA5JhzUoFMCSYpb7uGoQC/2C9eLLlExjSL50USTwNknx7NJKseNsZ1UnYPzVBOPv7DqGtI7Xuap80PloePuJ0kIJBL0SXGQFG1pw2zpb8KLy1OAcKLo9Q5clKNU3xAzl7FWs4JjvYjUfqTeUM1JLUx2CRqZYdzAVkxWBEfIE87hl96r0IWwYMOMOg4YH4VZ8944YNdPtUQTf4pGmaYNN11QVUTX/1mM/S3N8mbDF
I know that this is a valid RSA public key, but what I really to get is n and e out of it. However, when I attempt to import it into my python code as so
import Crypto.PublicKey import RSA
f = open('MyRSAKey.txt', 'r')
Temp_Key = f.read()
Final_Key = RSA.importKey(Temp_Key)
n = Final_Key.n
e = Final_key.e
I get an error that says
ValueError: RSA key format is not supported
Is there something that I am missing? I just really to find some way to get a hold of n and e so I can store them for future use
I just added
"ssh-rsa " + "AAAAB..."
and it worked

Decrypting PGP using gnupg in Python

I am trying to decrypt a PGP file using this module:
http://packages.python.org/python-gnupg/
Here is my code snippet:
#!/usr/bin/python
import gnupg
gpg = gnupg.GPG(gnupghome='C:\\Users\\GSquire\\Desktop\\GnuPG',
gpgbinary='C:\\Users\\GSquire\\Desktop\\GnuPG\\pub\\gpg.exe',
keyring='C:\\Users\\GSquire\\Desktop\\GnuPG\\secring.skr')
with open('.\\tranx08022012.txt.pgp', 'rb') as f:
status = gpg.decrypt_file(f, passphrase='passphrase', output='out.txt')
I am using the latest version of the module, and Python 2.6.6. I thought I could just use the secure ring file to decrypt it because that is obviously needed by the file. It outputs this when I run the script:
ok: False
status:
stderr:
gpg: expected public key but found secret key - must stop
Isn't it true that the secure key is what decrypts the file? Thanks for the help!
The error you're getting is because you're passing the secret keyring's filename in the keyring parameter. That parameter is only for the public keyring. Unfortunately, there doesn't seem to be an alternative parameter to specify a secret keyring file.
By default, GnuPG will look for secret keys in secring.gpg in the gnupghome folder you specify, so you can probably rename your secret key file and get it to work.

Categories