Open olivierch opened 11 years ago
It's inherent to the math underlying the SRP algorithm. If you haven't already, I suggest you take a look at the end of the pysrp documentation. There's a description of the algorithm there that will hopefully shed some light on the issue. Ultimately and at the end of the exchange, both endpoints are left with a unique value that is known only to them and that may be used for symmetric encryption. I'm not really sure how to explain further. Is you question based more on and understanding of the mathematics or a understanding of the implementation?
On Fri, Sep 27, 2013 at 12:33 AM, Olivier Chaussavoine < notifications@github.com> wrote:
I did not see how could be obtained a large key that was known at the end of exchanges and known only by both sides. We cannot perform symmetric encryption without it. Could you explain that?
— Reply to this email directly or view it on GitHubhttps://github.com/cocagne/pysrp/issues/3 .
You are right, I found the method get_session_key() that solved the problem. I was wondering which kind of symmetric cipher could be used when this key is set, I chose Crypto.Cipher.AES and initialized it like this:
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
def getAES(pwd,iv):
_hash = SHA256.new()
_hash.update(pwd)
return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])
where iv is returned by the method get_session_key(). The password is hashed in order to obtain a key with 32 bytes. I just use the methods encrypt() and decrypt() of the object returned by getAES(pwd,iv).
Have you an opinion on this implementation?
AES is a good choice for the encryption algorithm. It's pretty standard and has a good security rating. You should use the SRP session key as the AES key and the IV should, ideally, be random data. The IV isn't secret information and you can send it across the network to the receiver so they can use the same value.
A word of caution here though. The likelihood that you'll make a mistake with your use of encryption is close to 100%. It's extremely difficult to achieve good security even for cryptography experts. If your use-case really does require tight security, I'd suggest that you first try and closely follow the encryption approach used by some other protocol. You could, for example, use an encryption model that closely follows TLS packet encryption. Second and after you've done the first, try and find someone with a good crypto background to vet your implementation.
Good luck.
Tom
On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine < notifications@github.com> wrote:
You are right, I found the method get_session_key() that solved the problem. I was wondering which kind of symmetric cipher could be used when this key is set, I chose Crypto.Cipher.AES and initialized it like this:
from Crypto.Cipher import AESfrom Crypto.Hash import SHA256 def getAES(pwd,iv): _hash = SHA256.new() _hash.update(pwd) return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])
where iv is returned by the method get_session_key(). The password is hashed in order to obtain a key with 32 bytes. I just use the methods encrypt() and decrypt() of the object returned by getAES(pwd,iv).
Have you an opinion on this implementation?
— Reply to this email directly or view it on GitHubhttps://github.com/cocagne/pysrp/issues/3#issuecomment-25230442 .
I beleived the result obtained by get_session_key() was random and only known by both sides. Am I wrong?
Your second argument is very wise and respectfull, but I do very simple things with that: 1) srp challenge giving me a session key, 2) symetric encryption with AES using this session key.
2013/10/1 cocagne notifications@github.com
AES is a good choice for the encryption algorithm. It's pretty standard and has a good security rating. You should use the SRP session key as the AES key and the IV should, ideally, be random data. The IV isn't secret information and you can send it across the network to the receiver so they can use the same value.
A word of caution here though. The likelihood that you'll make a mistake with your use of encryption is close to 100%. It's extremely difficult to achieve good security even for cryptography experts. If your use-case really does require tight security, I'd suggest that you first try and closely follow the encryption approach used by some other protocol. You could, for example, use an encryption model that closely follows TLS packet encryption. Second and after you've done the first, try and find someone with a good crypto background to vet your implementation.
Good luck.
Tom
On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine < notifications@github.com> wrote:
You are right, I found the method get_session_key() that solved the problem. I was wondering which kind of symmetric cipher could be used when this key is set, I chose Crypto.Cipher.AES and initialized it like this:
from Crypto.Cipher import AESfrom Crypto.Hash import SHA256 def getAES(pwd,iv): _hash = SHA256.new() _hash.update(pwd) return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])
where iv is returned by the method get_session_key(). The password is hashed in order to obtain a key with 32 bytes. I just use the methods encrypt() and decrypt() of the object returned by getAES(pwd,iv).
Have you an opinion on this implementation?
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25230442> .
— Reply to this email directly or view it on GitHubhttps://github.com/cocagne/pysrp/issues/3#issuecomment-25422744 .
Olivier Chaussavoine
Oh, ok. I think I follow you now. You're intentionally using a derivative of the user's password as the AES encryption key and using the SRP session key to avoid having to explicitly send the IV over the network. It sounds reasonable and I can't think of anything specifically wrong with that approach but I would have a few concerns about taking this approach for one of my projects. Specifically:
The last point there is a little fuzzy but crypto is so easy to get wrong it's almost always a good idea to follow the common practice unless you have a compelling reason to do otherwise. That said though, your approach might be fine. It looks like it should be but I'm far from a security expert.
Tom
On Tue, Oct 1, 2013 at 11:53 AM, Olivier Chaussavoine < notifications@github.com> wrote:
I beleived the result obtained by get_session_key() was random and only known by both sides. Am I wrong?
Your second argument is very wise and respectfull, but I do very simple things with that: 1) srp challenge giving me a session key, 2) symetric encryption with AES using this session key.
2013/10/1 cocagne notifications@github.com
AES is a good choice for the encryption algorithm. It's pretty standard and has a good security rating. You should use the SRP session key as the AES key and the IV should, ideally, be random data. The IV isn't secret information and you can send it across the network to the receiver so they can use the same value.
A word of caution here though. The likelihood that you'll make a mistake with your use of encryption is close to 100%. It's extremely difficult to achieve good security even for cryptography experts. If your use-case really does require tight security, I'd suggest that you first try and closely follow the encryption approach used by some other protocol. You could, for example, use an encryption model that closely follows TLS packet encryption. Second and after you've done the first, try and find someone with a good crypto background to vet your implementation.
Good luck.
Tom
On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine < notifications@github.com> wrote:
You are right, I found the method get_session_key() that solved the problem. I was wondering which kind of symmetric cipher could be used when this key is set, I chose Crypto.Cipher.AES and initialized it like this:
from Crypto.Cipher import AESfrom Crypto.Hash import SHA256 def getAES(pwd,iv): _hash = SHA256.new() _hash.update(pwd) return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])
where iv is returned by the method get_session_key(). The password is hashed in order to obtain a key with 32 bytes. I just use the methods encrypt() and decrypt() of the object returned by getAES(pwd,iv).
Have you an opinion on this implementation?
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25230442> .
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25422744> .
Olivier Chaussavoine
— Reply to this email directly or view it on GitHubhttps://github.com/cocagne/pysrp/issues/3#issuecomment-25467976 .
You got it! You let me think it could be possible to avoid storing a clear password in the server database. That was not my requirement. Do we just need to compute the verifier and store it with uname in the database for all future sessions, or each time a new session is initiated? I chose the second solution storing only uname and password in the database. I am not a security expert either, and more afraid by taking the risk of sending a clear IV on the network than storing clear passwords on my database.
Olivier
2013/10/2 cocagne notifications@github.com
Oh, ok. I think I follow you now. You're intentionally using a derivative of the user's password as the AES encryption key and using the SRP session key to avoid having to explicitly send the IV over the network. It sounds reasonable and I can't think of anything specifically wrong with that approach but I would have a few concerns about taking this approach for one of my projects. Specifically:
- This approach requires either storing the raw user's password in the server's database or both the SRP verifier and the SHA256 hash of the password. Were you to use the session key as the AES key, only the SRP verifier would be required.
- It is significantly easier to recover the user's password from a compromised SHA256 hash of the user's password than it is to recover it from the SRP verifier (which is salted)
- It goes against the common practice of using the SRP session key as the symmetric encryption key.
The last point there is a little fuzzy but crypto is so easy to get wrong it's almost always a good idea to follow the common practice unless you have a compelling reason to do otherwise. That said though, your approach might be fine. It looks like it should be but I'm far from a security expert.
Tom
On Tue, Oct 1, 2013 at 11:53 AM, Olivier Chaussavoine < notifications@github.com> wrote:
I beleived the result obtained by get_session_key() was random and only known by both sides. Am I wrong?
Your second argument is very wise and respectfull, but I do very simple things with that: 1) srp challenge giving me a session key, 2) symetric encryption with AES using this session key.
2013/10/1 cocagne notifications@github.com
AES is a good choice for the encryption algorithm. It's pretty standard and has a good security rating. You should use the SRP session key as the AES key and the IV should, ideally, be random data. The IV isn't secret information and you can send it across the network to the receiver so they can use the same value.
A word of caution here though. The likelihood that you'll make a mistake with your use of encryption is close to 100%. It's extremely difficult to achieve good security even for cryptography experts. If your use-case really does require tight security, I'd suggest that you first try and closely follow the encryption approach used by some other protocol. You could, for example, use an encryption model that closely follows TLS packet encryption. Second and after you've done the first, try and find someone with a good crypto background to vet your implementation.
Good luck.
Tom
On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine < notifications@github.com> wrote:
You are right, I found the method get_session_key() that solved the problem. I was wondering which kind of symmetric cipher could be used when this key is set, I chose Crypto.Cipher.AES and initialized it like this:
from Crypto.Cipher import AESfrom Crypto.Hash import SHA256 def getAES(pwd,iv): _hash = SHA256.new() _hash.update(pwd) return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])
where iv is returned by the method get_session_key(). The password is hashed in order to obtain a key with 32 bytes. I just use the methods encrypt() and decrypt() of the object returned by getAES(pwd,iv).
Have you an opinion on this implementation?
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25230442> .
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25422744> .
Olivier Chaussavoine
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25467976> .
— Reply to this email directly or view it on GitHubhttps://github.com/cocagne/pysrp/issues/3#issuecomment-25510951 .
Olivier Chaussavoine
You only need to calculate the verifier once and it may be used for all future SRP authentication attempts. As for the IV, it's not a secret value so you can send it over the network in the clear and without concern. In fact, when AES encryption is being used in DTLS (the UDP version of SSL), each packet has a random IV prepended to the encrypted data block. All you need to do is make sure the IV comes from a good source of random data. On Linux systems, you can just read the appropriate number of bytes from /dev/urandom. There's a section on Initialization Vectors used in block ciphers on Wikipedia that might help: http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Initialization_vector_.28IV.29
As for storing the passwords directly in the database, please try to avoid this if at all possible. It seems innocuous but remember that people tend to reuse passwords even when you tell them not to. If your database is somehow hacked, it could lead to bigger, seemingly unrelated problems when the attackers test those username,password combinations on other sites. Financial websites aside, even just gaining access to someone's web e-mail account could give an attacker enough personal information for identity theft.
Cheers,
Tom
On Wed, Oct 2, 2013 at 1:25 AM, Olivier Chaussavoine < notifications@github.com> wrote:
You got it! You let me think it could be possible to avoid storing a clear password in the server database. That was not my requirement. Do we just need to compute the verifier and store it with uname in the database for all future sessions, or each time a new session is initiated? I chose the second solution storing only uname and password in the database. I am not a security expert either, and more afraid by taking the risk of sending a clear IV on the network than storing clear passwords on my database.
Olivier
2013/10/2 cocagne notifications@github.com
Oh, ok. I think I follow you now. You're intentionally using a derivative of the user's password as the AES encryption key and using the SRP session key to avoid having to explicitly send the IV over the network. It sounds reasonable and I can't think of anything specifically wrong with that approach but I would have a few concerns about taking this approach for one of my projects. Specifically:
- This approach requires either storing the raw user's password in the server's database or both the SRP verifier and the SHA256 hash of the password. Were you to use the session key as the AES key, only the SRP verifier would be required.
- It is significantly easier to recover the user's password from a compromised SHA256 hash of the user's password than it is to recover it from the SRP verifier (which is salted)
- It goes against the common practice of using the SRP session key as the symmetric encryption key.
The last point there is a little fuzzy but crypto is so easy to get wrong it's almost always a good idea to follow the common practice unless you have a compelling reason to do otherwise. That said though, your approach might be fine. It looks like it should be but I'm far from a security expert.
Tom
On Tue, Oct 1, 2013 at 11:53 AM, Olivier Chaussavoine < notifications@github.com> wrote:
I beleived the result obtained by get_session_key() was random and only known by both sides. Am I wrong?
Your second argument is very wise and respectfull, but I do very simple things with that: 1) srp challenge giving me a session key, 2) symetric encryption with AES using this session key.
2013/10/1 cocagne notifications@github.com
AES is a good choice for the encryption algorithm. It's pretty standard and has a good security rating. You should use the SRP session key as the AES key and the IV should, ideally, be random data. The IV isn't secret information and you can send it across the network to the receiver so they can use the same value.
A word of caution here though. The likelihood that you'll make a mistake with your use of encryption is close to 100%. It's extremely difficult to achieve good security even for cryptography experts. If your use-case really does require tight security, I'd suggest that you first try and closely follow the encryption approach used by some other protocol. You could, for example, use an encryption model that closely follows TLS packet encryption. Second and after you've done the first, try and find someone with a good crypto background to vet your implementation.
Good luck.
Tom
On Fri, Sep 27, 2013 at 3:34 AM, Olivier Chaussavoine < notifications@github.com> wrote:
You are right, I found the method get_session_key() that solved the problem. I was wondering which kind of symmetric cipher could be used when this key is set, I chose Crypto.Cipher.AES and initialized it like this:
from Crypto.Cipher import AESfrom Crypto.Hash import SHA256 def getAES(pwd,iv): _hash = SHA256.new() _hash.update(pwd) return AES.new(_hash.digest(),AES.MODE_CBC,iv[:16])
where iv is returned by the method get_session_key(). The password is hashed in order to obtain a key with 32 bytes. I just use the methods encrypt() and decrypt() of the object returned by getAES(pwd,iv).
Have you an opinion on this implementation?
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25230442> .
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25422744> .
Olivier Chaussavoine
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25467976> .
— Reply to this email directly or view it on GitHub< https://github.com/cocagne/pysrp/issues/3#issuecomment-25510951> .
Olivier Chaussavoine
— Reply to this email directly or view it on GitHubhttps://github.com/cocagne/pysrp/issues/3#issuecomment-25515678 .
To be clear to anyone reading this the correct approach is to:
End.
I did not see how could be obtained a large key that was known at the end of exchanges and known only by both sides. We cannot perform symmetric encryption without it. Could you explain that?