How to export a Crypto key in python? - python-3.x

I want to encrypt files fore secure storage, but the problem is, I don't know how to store the key to decrypt the files afterwards.
Code:
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto import Random
import ast
random_generator = Random.new().read
key = RSA.generate(1024, random_generator)
encrypteds = str()
for text in open('passwords.log', 'rb').readlines():
publickey = key.publickey()
encryptor = PKCS1_OAEP.new(publickey)
encrypted = encryptor.encrypt(text)
decryptor = PKCS1_OAEP.new(key)
decrypted = decryptor.decrypt(ast.literal_eval(str(encrypted)))
print(publickey)
encrypteds+=str(encrypted)+'--|--'
with open('passwords_encrypted.log', 'w') as out:
out.write(str(encrypted))

I look at your code but RSA currently many issues of security so please considers another type of encryption as read attentively and follow. There are two many symmetrical and asymmetrical encryption in cryptography and cryptanalysis scheme you could apply for secure encryption decryption key derivation key sharing between parties or an entities etc. E.g AES Chaha20Poly1305 AESGCM but its depends on on what kind of encryption scheme you want to apply. It is sensitive critical point. please have look you definitely find your answer as well check and suggest you to look at the others symmetric encryption which have good security as compare to RSA. http://legrandin.github.io/pycryptodome/Doc/3.3.1/Crypto.Cipher-module.html

The way you're encrypting data makes no sense. Asymmetric encryption can only encrypt a small, fixed amount of data. Never use asymmetric encryption such as RSA-OAEP for anything other than a symmetric key, and use that symmetric key to encrypt the actual data. For the symmetric encryption, use a proper AEAD mode such as AES-GCM or ChaCha20-Poly1305. This is called hybrid encryption.
Other things that are wrong with your code:
A 1024-bit RSA key is not enough for security: 2048-bit is a minimum, and you should prepare to move away from RSA because its key sizes don't scale well. (Feel free to use 1024-bit keys for testing and learning, just don't use anything less than 2048-bit for RSA in production.)
The encryption is a binary format, but you join up lines as if they were text. Text or binary: pick one. Preferably use a well-known format such as ASN.1 (complex but well-supported) for binary data or JSON for text. If you need to encode binary data in a text format, use Base64.
If this is for real-world use, scrap this and use NaCl or libsodium. In Python, use a Python wrapper such as libnacl, PyNaCl, pysodium or csodium. Use a public-key box. The Python APIs are slightly different for each Python wrapper, but all include a way to export the keys.
If this is a learning exercise, read up on hybrid encryption. Look inside libsodium to see how to do it correctly. Key import and export is done with the methods import_key and export_key. Symmetric encryption starts with Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_GCM) or Crypto.Cipher.ChaCha20_Poly1305.new(key) (Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_GCM, nonce=nonce) or Crypto.Cipher.ChaCha20_Poly1305.new(key, nonce=nonce) for decryption).

Related

How to do 1-of-X or Y-of-X public key based encrypt/ decrypt in NodeJs?

I would like to be able to encrypt data using public keys, and decrypt the encrypted data using private keys.
Encryption essentially needs to accept inputs:
Clear data to be encrypted
A list of several public keys
The minimum number of private keys corresponding to those public keys that are needed to decrypt the encrypted
How can this be done in NodeJs?
Scenarios
By way of concrete scenarios, where there are 5 users (A - E) with crypto key pairs in the system.
A 1-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey], 1) (1-of-2)
decrypted = crypto_decrypt(encrypted, [A.privateKey])
success: decrypted === clearText
because A.publicKey was used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey])
failure: unable to decrypt
because C.publicKey was not used in encryption
A Y-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey, C.publicKey], 2) (2-of-3)
decrypted = crypto_decrypt(encrypted, [A.privateKey, C.privateKey])
success: decrypted === clearText
because both A.publicKey and C.publicKey was used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey, E.privateKey])
failure: unable to decrypt
because while C.publicKey was used in encryption, E.publicKey was not
Ideally...
At minimum I need to be able to support the 1-of-X scenario, but if Y-of-X is also possible, that would be better
What the actual key pairs are is not so important here, could be RSA, could be any of the elliptic curves. If the method supports a number of different ones, and allows one to pick, that would be better
Preferably not tied to the use of any particular toolset or framework
PGP can do this.
Specifically for node, openpgpjs has a section in the README - https://github.com/openpgpjs/openpgpjs#encrypt-and-decrypt-string-data-with-pgp-keys - which could be condensed into:
const encryptedText = await openpgp.encrypt({ message: clearText, publicKeys });
const decryptedText = await openpgp.decrypt({ message: encryptedText, privateKeys });
However:
for number of keys required to decrypt, it only supports the 1 of many scenario, not the more general some of many scenario you'd ideally want
supports both RSA and many elliptic curve based keys, but the key format is designed for use by PGP, as the name of the library implies (so it is specific to the PGP toolchain)
As noted by Luke Joshua Park in the comments, this sounds like a textbook use case for a secret sharing scheme. Specifically, I would recommend that you:
Generate a random AES (or other symmetric cipher) key. Make sure to use a cryptographically secure RNG (such as Crypto.randomBytes()) for this, since an attacker who can guess this key can also break the entire scheme!
Encrypt the data with this key, using an authenticated encryption mode such as AES-SIV (as provided e.g. by miscreant).
Split the AES key into multiple shares using Shamir's secret sharing scheme with the desired reconstruction threshold. (Some JS implementations I found with a quick Google search include secrets.js, jsss and ThresholdJS.)
Encrypt each share using a different user's public key.
Send each user their encrypted share and a copy of the AES-encrypted data.
Disclaimer: I have not reviewed the security or correctness of any of the APIs or libraries linked above. The cryptographic techniques they claim to use appear to be sound and suitable for this task, but I cannot guarantee that they have been implemented safely and correctly. Caveat emptor.
To decrypt the data, each user can first decrypt their share of the AES key using their private key, and a sufficient number of the decrypted shares can then be combined (using the same implementation of Shamir's secret sharing as used to create them) to reconstruct the original AES key, which can then be used to decrypt (and verify the integrity of) the data.
Note that Shamir's secret sharing implicitly assumes that the users who combine their shares to reconstruct the secret will trust each other and not lie about their shares or otherwise misbehave. If that's not necessarily true, there are various ways for a malicious user to trick the others — perhaps most simply by waiting for everyone else to reveal their share to them and then refusing to reveal their own share to the others. In general, preventing such attacks is all but impossible without the help of some kind of a mutually trusted party.
At the very least, though, using an encryption mode like AES-SIV with built-in authentication should ensure that users will detect if the reconstructed AES key is incorrect, since the decryption will then fail. If you want to be extra sure of this, you may wish to also send each of the users a secure cryptographic hash (e.g. SHA-512) of the AES key, so that they can verify its correctness before attempting decryption.

WebCrypto: Safe conversion from RSA-OAEP to RSA-PSS

WebCrypto supports RSA but forces you to choose the padding scheme for the different operations you can perform. RSA can perform both signing/verification and encryption/decryption (+key wrapping) but that is not very possible with the webcrypto API.
When I generate an RSA key using RSA-OAEP, the same key could be used for RSA-PSS, however there's no clear way to move around those using the webcrypto API.
My original thought was to take these steps to convert keys:
export the key using exportKey with jwk
"fix" alg from (for example) RSA-OAEP-512 to PS512
"fix" key_ops
a. encrypt-> verify
b. decrypt -> sign
Import the "fixed" key with the correct algorithm
This system breaks down when the key is not-exportable, which I want to do for extra security of private keys (malicious scripts, self-xss, etc).
What would be a good way to "convert" between algorithm types but keeping the key without the ability to export?
The webcrypto API do not allow to use a key for signing and encryption. Probably because this practice is not recommended. See this answer https://crypto.stackexchange.com/a/12138/42888
it is safe, cryptographically speaking, to use the same RSA key pair for signature and encryption, provided that the key pair is used safely for signature and used safely for encryption.
However this is a bad idea for a different reason: key management. Signature keys and encryption keys have different requirements in terms of backups, access control, repudiation, etc. The fallback for a signature key in case of a catastrophic event is to destroy it to avoid future forgeries, so a signature key does not need to be backed up extensively. Conversely, the fallback for an encryption key is to keep it around to decrypt existing documents, so it needs to be backed up reliably.
To answer your question, you could:
Generate the RSA key as extractable,
Export it to pcks8 or jwk
Import it twice as non-extractable: key1-> RSA-OAEP, key2-> RSA-PSS
Destroy the original and extractable key
Then, the resulting keys are equal and non-extractable, and the original key has only be managed in browser memory.
Since you are going to get two keys in the browser, if the receivers of the public key are different, consider to generate distinct keys for signing and encryption

How to securely encrypt many similiar chunks of data with the same key?

I'm writing an application that will require the following security features: when launching the CLI version, you should pass some key to it. Some undefined number of chunks of data of the same size will be generated. It needs to be stored remotely. This will be a sensitive data. I want it to be encrypted and accessible only by that one key that was passed to it initially. My question is, which algorithm will suit me? I read about AES but it says that
When you perform an encryption operation you initialize your Encryptor
with this key, then generate a new, unique Initialization Vector for
each record you’re going to encrypt.
which means I'll have to pass a key and an IV, rather than just the key and this IV should be unique for each generated chunk of data (and there is going to be a lot of those).
If the answer is AES, which encryption mode is it?
You can use any modern symmetric algorithm. The amount of data and how to handle your IVs is irrelevant because it applies no matter which symmetric algorithm you pick.
AES-128 is a good choice, as it isn't limited by law in the US and 128 bits is infeasible to brute force. If you aren't in the US, you could use AES-256 if you wanted to, but implementations in Java require additional installations.
You say you are going to generate n many chunks of data (or retrieve, whatever).
You could encrypt them all at once in CBC mode, which keeps AES as a block cipher, and you'll only end up with one IV. You'll need an HMAC here to protect the integrity. This isn't the most modern way, however.
You should use AES in GCM mode as a stream cipher. You'll still have one single IV (nounce) but the ciphertext will also be authenticated.
IVs should be generated randomly and prepended to the ciphertext. You can then retrieve the IV when it is time to decrypt. Remember: IVs aren't secret, they just need to be random!
EDIT: As pointed out below, IVs should be generated using a crypto-secure random number generator. IVs for CTR based modes, like GCM, only need to be unique.
In summary, what you are worried about shouldn't be worried about. One key is fine. More than one IV is fine too, but there are ways to do it with just one. You will have to worry about IVs either way. Don't use ECB mode.

Best practice for decrypting text file using SALT, SEED, SecretKey in android

I am new to security issues. I am trying to implement some basic (limited) protection of intellectual property in an android app by encrypting text assets. To do this, I have implemented the SimpleCrypto class described by S.Saurel here http://www.ssaurel.com/blog/how-to-use-cryptography-in-android-applications-2/. I plan to encrypt the data using a separate program and include the encrypted data as assets files, then decrypt them for use in the app. My question is what is the best practice for dealing with the SALT string and SEED string that are needed to decrypt the files? Should they be generated at run time or stored somehow? Should they be included in the crypto class, or generated elsewhere in the app and passed to the crypto class?
Thanks in advance!
In this implementation "seed" is what you would think of as "password", and since you're not going to ask the user to provide a password, you can hardcode it, or store it in a file, or request it from a server at runtime, or whatever else. Be aware that a smart attacker will most likely be able to get at this password and use it to generate their own decryption key for your ciphertexts.
Salt is a non-secret value that acts as an initialization vector for encryption. Best-practice would dictate that you generate a random salt per cleartext, then provide the ciphertext and unencrypted seed to the client. The IV is typically dependent on the block size of your cipher used, and in your example there you're generating a 256-bit key, so you should generate a random 256-bit (64-byte) salt per cleartext and ship it with the ciphertext. You could do something as simple as producing a final string which is:
[2 bytes indicating length of salt][salt][ciphertext]
Then from that you can get your seed and ciphertext for decryption.

RSA: Encrypting message using multiple keys

Is it possible to get additional security by encrypting a message using 2 or more RSA keys?
EDIT: A few clarifications:
The context I am most interested in doing this for is encrypting a randomly generated symmetric key.
I don't want to limit the question to encrypting twice in a row; the purpose is to avoid the high computational cost of large RSA keys. Using less straightforward tactics such as breaking the message into parts and encrypting them separately should be considered as an option.
It should be assumed that getting only part of the message is acceptable.
If you know of any publications where this is discussed specifically by an expert, or algorithms that use multiple RSA keys, then please contribute.
No.
It is not safe to do thought experiments regarding cryptography. You are advised to keep narrowly to the path trodden by the experts.
And when the experts want to protect something better, they use a bigger key-size (at least 2048 bits is required, smaller certificates are insufficient for any peace of mind) or use elliptic curve certificates in preference to RSA.
Incidentally, you're remember that your message body is typically encrypted with a symmetric cipher and a random key, and that just this random key is encrypted with the public key of the recipient. Double-encrypting this secret key won't make this secret key longer, and won't impact an attacker's ability to brute-force that.
Quantum cryptography - I mention it only as an exciting aside, you need not factor this into your choice - promises interesting things for the keysizes: the RSA keys will be wiped out by Shor's algorithm, but the symmetric keys (Grover's) will be only half-lengthed (128-bits will be equiv to 64-bits, so will be crackable). There is of course debate about whether such quantum machines can be implemented etc etc :)
No.
If Key A is compromised than encrypted with A+B will protect against the compromise, but outside that special case, you get no additional benefit.
Composing ciphers
Say you have an encryption function E(M, K), where M is the plaintext message and K is the key. Say no known vulnerabilities exist in E.
You generate two completely unrelated keys K1 and K2.
It is guaranteed that if you compose them in the form E(E(M, K1), K2), it is impossible to actually lose security this way. If it was possible to lose security from encrypting E(M, K1), be it with K2 or any other key, the is cipher broken, because an attacker could just do E(E(M, K1), KF) where KF is any key the attacker wishes to choose.
For more info see here.
Encrypting every second block with a different key
The implications here are obvious. Assuming you are using properly composed cryptographic primitives with both encryption function:key combinations, if you encrypt every second block with a different key out of the set of two keys, the attacker can only decrypt the blocks he has the key for.
Yes!
But do not use raw encryption. Use RSA encryption schema. Instead of reencrypting the encrypted message with the second key, which might have weakening effet (I don't know), use the shared secret algorithm to split your secret in two. The shared secret algorithm make it possible to split a secret in n pieces and ensures that if an attacker manages to get n-1 pieces he knows nothing of the secret. So don't simply split the secret in two.
You can then have more then 2 RSA keys. Another powerful property of the shared secret algorithm is that it is possible to spread the secret over n pieces and require only m pieces, with m smaller than n, to recover the secret. This makes the secret recovery more robust to loss of pieces.
Look here for more information on shared secret: http://en.wikipedia.org/wiki/Shared_secret
In additional to the answers given, it also simply doesn't work unless you do some patching. Very simply, one of the moduli must be larger than the other. If you perform RSA mod the larger modulus first and mod the smaller last you lose information and cannot guarantee successful decryption. The obvious patch is to always encrypt with the smaller modulus first. Of course, you have to perform decryption in the opposite order. Another simple patch is choose moduli that a very close together in size, so that the probability that you encounter a ciphertext that cannot be uniquely decrypted is vanishingly small.

Resources