I've installed pyCrypto package on Python 2.7.1 to do some cryptography operations.
Q1:
The operation that I want to do is encrypting some data with private Key (instead of public Key). It seems that this library can't do it. Am I right? If so, is there any library capable to do that?
Q2:
In the documentation it is not mentioned which hash algorithm is used to calculate the signature! How can I find out which hash function is used for sign method?
Q3:
You see a part of documentation about encrypt method:
encrypt(self, plaintext, K)
Encrypt a piece of data with RSA.
Parameters:
plaintext (byte string or long) - The piece of data to
encrypt with RSA. It may not be numerically larger than the RSA module
(n).
(Censored!)
As you see above, the input data is limited to those that are not numerically larger than the RSA module. Does this mean that I can't encrypt 0x21...(257 bytes) with an RSA key pair with module = 0x11...(257 bytes) (for example) because 0x21 is greater than 0x11? If so, why? Isn't it weird to compare the values before encryption each time?! Or it is only meant that the data length must be equal or smaller than the module length?
In public key cryptography, you do not encrypt with the private key -- you always use the public key. Otherwise, since the public key is "public", anybody could decrypt the ciphertext.
You might be tempted to use the public and private keys interchangeably, but generally, given the private key, you can figure out the public key without much work. So, if you give someone the private key thinking that you will keep the public key safe, well, it won't be safe.
When they say not larger than the modulus, they mean the size in bytes. It will actually be smaller that the size of the modulus (256 bytes for a 2048 bit RSA key pair). But the data should actually be smaller than the modules because you will want to always pad the data. Padding, for example with OAEP padding, randomizes the ciphertext. Each time you encrypt the same plaintext, you get different ciphertext that looks random. This is important because otherwise the ciphertext is weak and open to attack even if the attacker does not have the private key. So you want to leave some room for the data plus the padding to fit in the modulus (e.g. 256 bytes).
Generally, you sign with the private key. In RSA, this actually does "encrypt" with the private key, but I don't think you will find "encrypt with private key" in any popular API.
I am not familiar with pyCrypto but it looks to me like you pick your favorite hash when signing. You hash yourself, and give the digest to the sign function, as far as I can tell from examples I've googled.
As a solution I came across with this:
https://www.php2python.com/wiki/function.openssl-private-encrypt/
Be careful though to understand the implications of using private key to encrypt.
In my case I want to share an encryption key that can be read by a software who has the public key hard coded. I could have use signing, however I prefer the key not to be shared as-is and therefore needs encryption. Only alternative would have been to setup PKI or PGP.
Related
I found this code snippet, here it is serializing an RSA private key into an encrypted cipher text. I wanted to know which algorithm in this code serialization.BestAvailableEncryption(b'mypassword') will be used to do so.
from cryptography.hazmat.primitives import serialization
pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword')
)
It's up to the implementation of the private_key object. The BestAvailableEncryption just says that you don't have a specific preference and would like the library to pick an encryption type for the key for you.
In the OpenSSL backend (which is the only one, it seems), the best encryption is chosen here, where it currently selects the 'aes-256-cbc' cypher. That may change in future versions. Leaving the choice up to the implementation is the reason to have the BestAvailableEncryption class.
I found the Python package to encrypt some data and see this in python Cryptography:
It is possible to use passwords with Fernet(symmetric key). To do this, you need to run the password through a key derivation function such as PBKDF2HMAC, bcrypt or scrypt.
But, it turns out that a password works in the same way as a key(use password/key to en/decrypt). So why bother to use password instead of key itself?
I mean why not just use key itself:
from cryptography.fernet import Fernet
key = Fernet.generate_key()
token = Fernet(key).encrypt(b"my deep dark secret")
Fernet(key).decrypt(token)
A password is something that can be remembered by a person whereas a key is usually not remembered, because it is long (at least 128 bit or Hex-encoded in 32 characters) and is supposed to be really random (indistinguishable from random noise). If you want to encrypt something with a key, but this key cannot be transmitted by asymmetric cryptography and instead should be given over the phone or should never be written anywhere, then you can't simply generate a random key and use that. You need have a password/passphrase in place to derive the key from.
Example 1:
A personal password safe like KeePass needs a key for encryption/decryption. A user will not be able to simply remember that key, therefore we have a much shorter password, which can be remembered. Now, the security lies in the fact that a slow key derivation function is used to derive a key from the password, so an attacker still has trouble brute-forcing the key even though it depends on a much shorter password.
Example 2:
You compress a document and use the encryption of the compression software. Now you can send the container via e-mail, but you can't send the password along with it. So, you call the person you've sent the e-mail to and tell them the password. A password is much easier to transmit than a long and random key in this way.
I'm looking to send a file to multiple people, but I also want them to know that:
The file has not been changed since I sent it to them.
They know that it was me who sent the file.
I'm coding in Python, so I was thinking of pulling in the file, taking a hash of it, and then encrypting the hash with my private key. I would send the original file along with this new file (probably just a .txt) to whoever I want. My friends could then decrypt the hash using my public key and compare it to a hash they take of the original file. I'd like to use something at least on the level of SHA-256. I do not want to use MD5 or SHA-1.
Note- The original file I am sending does not have to be encrypted, just looking for some integrity and non-repudiation.
Would this fulfill the two requirements above? And is there an easy way to implement this in Python?
I was thinking of pulling in the file, taking a hash of it, and then encrypting the hash with my private key
That's exactly what we commonly call signing or digital-signature, which fulfills your two requirements.
Would this fulfill the two requirements above?
Yes. Signing a message doesn't prevent it from being manipulated. It's only getting infeasible of generating a signature for a manipulated message without the private key.
And is there an easy way to implement this in Python?
Sure, pyCrypto supports RSA and DSA. You should try ed25519, though, because its signatures are smaller.
I have a function for encrypting with SHA-1 in Python, using hashlib. I take a file and encrypt the contents with this hash.
If I set a password for an encrypted text file can I use this password to decrypt and to restore the file with the original text?
Hashing functions are different than normal crypto algorithms. They are oftenly referred to as one-way ciphers, because the process data goes through is irreversible.
Differently than symmetric and assymetric encryption, hashes are used by asserting the hashed values themselves, instead of decrypting and asserting the plain-text values. To validate logins when you're using hashes, you'd hash the password the user just attempted to log in with and compare it with the hash you have on your DB. If they match, login is successful.
Cracking hashes involves guessing hashing various different strings and trying to match hashed values to the ones illegally obtained from a DB. There are lists available on the internet with millions of already hashed values to make hash cracking easier, those are known as Rainbow Tables and they can be easily countered with the use of Salts.
It's also worth noting that since hashing algorithms are able to digest GBs of data into significantly smaller strings, mathematically, two different values may have identical hashes. Even though this is very rare, it is an existing problem, and its known as Hash Collision.
If hashing was reversible, hard drives would be reduntant since we would be able to hash thousands of GBs into a small string of text and reverse them as we pleased. It would allow for data compression and storage in ways that violate physics.
Related Wikipedia Articles:
Hashing Algorithms: http://en.wikipedia.org/wiki/Hash_function
Rainbow Tables: http://en.wikipedia.org/wiki/Rainbow_table
Salts: http://en.wikipedia.org/wiki/Salt_(cryptography)
Collision: http://en.wikipedia.org/wiki/Collision_(computer_science)
Symmetric Encryption: http://en.wikipedia.org/wiki/Symmetric-key_algorithm
Assymetric Encryption: http://en.wikipedia.org/wiki/Public-key_cryptography
SHA-1 is not an encryption algorithm, it's a hashing algorithm. By definition, you can't "decrypt" anything that was hashed with the SHA-1 function, it doesn't have an inverse.
If you have an arbitrary hashed password, there's very little you can do to retrieve the original password - If you're lucky, the password could be in a database of reverse hashes, but that's as far as you can go.
And the message extraction algorithm expects the original password to perform the verification - the algorithm will hash the provided plain-text password and compare it against the stored hashed password, only if they're equal the plain-text message will be revealed.
Hash functions are one way tickets. You cannot use them for encryption.
Hash function algorithms are realised through modulo, xor and other familiar (one way) operations.
You may try to find what argument was used to generate hash but in theory you will never be 100% sure it is the correct value.
For example try with a really simple (useless in cryptography) hash function modulo 10. This function returns ten different values. If it's 7 you may guess the entry was 7 or 137 and 1234567. Same with md5, sha1 and better ones.
As you can see, in the case when you are using hash function that returns only 40 bytes with files that are much bigger (maybe even few hundred megabytes) there in theory exists infinite numbers of files for each possible hash.
Is there a python library that supports (symmetric) encryption of data with the possibility of using multiple decryption keys.
I have (sensitive) user data that must be stored encrypted in a database, but it must be possible for multiple 3rd parties to access the data without giving them all the same secret.
This could be implemented by generating a random key K, encrypt the original data D to get D_K. Then I encrypting K with as many access keys (ak_1 to ak_n) as needed, store them for later use and destroy K. Whenever a 3rd party tries to access D the submit ak_i and I use it to decrypt K and us it to decrypt D_K to get D.
However, it would be nice to have a implemented since a) I don't like to reinvent the wheel and b) this is security and you probably won't get it 100% right.
Due to the confusion and issues surrounding export controls of hard encryption, there's not a lot of 3rd party libraries that directly provide this sort of higher-level explicit encryption scheme.
For the most part you're going to have to wrap the toolset of something like PyCrypto with your own key logic. Seeing as it's crypto we're talking about, however, I'd be remiss if I didn't point out the other libraries for lower-level hard encryption tools in Python.